Initial commit of MPACT-Sim codelab exercises
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5503eaf --- /dev/null +++ b/.gitignore
@@ -0,0 +1,7 @@ +bazel-bin +bazel-mpact-sim-codelabs +bazel-out +bazel-testlogs +external +.vscode +.bazelrc
diff --git a/BUILD b/BUILD new file mode 100644 index 0000000..87eb757 --- /dev/null +++ b/BUILD
@@ -0,0 +1,31 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Top level BUILD file for mpact_sim + +load("@rules_license//rules:license.bzl", "license") + +package( + default_applicable_licenses = [":license"], + default_visibility = ["//visibility:public"], +) + +license( + name = "license", + package_name = "mpact-riscv", +) + +licenses(["notice"]) + +exports_files(["LICENSE"])
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..fb086f1 --- /dev/null +++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,96 @@ +# Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of +experience, education, socio-economic status, nationality, personal appearance, +race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, or to ban temporarily or permanently any +contributor for other behaviors that they deem inappropriate, threatening, +offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +This Code of Conduct also applies outside the project spaces when the Project +Steward has a reasonable belief that an individual's behavior may have a +negative impact on the project or its community. + +## Conflict Resolution + +We do not believe that all conflict is bad; healthy debate and disagreement +often yield positive results. However, it is never okay to be disrespectful or +to engage in behavior that violates the project’s code of conduct. + +If you see someone violating the code of conduct, you are encouraged to address +the behavior directly with those involved. Many issues can be resolved quickly +and easily, and this gives people more control over the outcome of their +dispute. If you are unable to resolve the matter for any reason, or if the +behavior is threatening or harassing, report it. We are dedicated to providing +an environment where participants feel welcome and safe. + +Reports should be directed to *[Tor Jeremiassen](torerik@google.com)*, the +Project Steward(s) for *[MPACT-Sim](https://mpact.googlesource.com)*. It is the +Project Steward’s duty to receive and address reported violations of the code +of conduct. They will then work with a committee consisting of representatives +from the Open Source Programs Office and the Google Open Source Strategy team. +If for any reason you are uncomfortable reaching out to the Project Steward, +please email opensource@google.com. + +We will investigate every complaint, but you may not receive a direct response. +We will use our discretion in determining when and how to follow up on reported +incidents, which may range from not taking action to permanent expulsion from +the project and project-sponsored spaces. We will notify the accused of the +report and provide them an opportunity to discuss it before any action is taken. +The identity of the reporter will be omitted from the details of the report +supplied to the accused. In potentially harmful situations, such as ongoing +harassment or threats to anyone's safety, we may take action without notice. + +## Attribution + +This Code of Conduct is adapted from the Contributor Covenant, version 1.4, +available at +https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +Note: A version of this file is also available in the +[New Project repo](https://github.com/google/new-project/blob/master/docs/code-of-conduct.md). \ No newline at end of file
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..47634bc --- /dev/null +++ b/CONTRIBUTING.md
@@ -0,0 +1,33 @@ +# How to Contribute + +We'd love to accept your patches and contributions to this project. + +## Before you begin + +### Sign our Contributor License Agreement + +Contributions to this project must be accompanied by a +[Contributor License Agreement](https://cla.developers.google.com/about) (CLA). +You (or your employer) retain the copyright to your contribution; this simply +gives us permission to use and redistribute your contributions as part of the +project. + +If you or your current employer have already signed the Google CLA (even if it +was for a different project), you probably don't need to do it again. + +Visit <https://cla.developers.google.com/> to see your current agreements or to +sign a new one. + +### Review our Community Guidelines + +This project follows [Google's Open Source Community +Guidelines](https://opensource.google/conduct/). + +## Contribution process + +### Code Reviews + +All submissions, including submissions by project members, require review. We +use GitHub pull requests for this purpose. Consult +[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more +information on using pull requests. \ No newline at end of file
diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/LICENSE
@@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License.
diff --git a/README.md b/README.md new file mode 100644 index 0000000..c7014aa --- /dev/null +++ b/README.md
@@ -0,0 +1,34 @@ +# MPACT-Sim Codelabs + +This repoistory contains the codelab exercises for the MPACT-Sim codelabs. +These codelabs provide a tutorials on how to get started using MPACT-Sim to +create instruction set simulators. + +The codelabs guide you to write most of the required code to build an +instruction set simulator for the RiscV 32I instruction set (integer +instructions only). + +There are four directories that contain code and build targets for the coding +exercises : + +* `riscv_isa_decoder` <br /> + This directory contains the skeleton and solution for writing the + description file for the encoding independent instruction decoder. + +* `riscv_bin_decoder` <br /> + This directory contains the skeleton and solution for writing the + description file for the binary decoder. + +* `riscv_semantic_functions` <br /> + This directory contains the skeleton and solution for writing the + semantic functions that implement the instructions in the codelab. + +* `riscv_full_decoder` <br /> + This directory contains the skeleton and solution for writing the full + instruction decoder that integrates the decoders that were generated in + prior exercises. + +Additionally, there is a directory `other`, that contains support code that +is not part of the exercises, but allows a finished simulator to be built +and executed. A sample "Hellow World" executable is also provided. +
diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..8f1236c --- /dev/null +++ b/SECURITY.md
@@ -0,0 +1,4 @@ +To report a security issue, please use [https://g.co/vulnz](https://g.co/vulnz). +We use g.co/vulnz for our intake, and do coordination and disclosure here on +GitHub (including using GitHub Security Advisory). The Google Security Team will +respond within 5 working days of your report on g.co/vulnz. \ No newline at end of file
diff --git a/WORKSPACE b/WORKSPACE new file mode 100644 index 0000000..932e481 --- /dev/null +++ b/WORKSPACE
@@ -0,0 +1,157 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +workspace(name = "com_google_mpact-sim-codelabs") + +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_file", "http_archive") +load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") + +# Additional bazel rules. +http_archive( + name = "bazel_skylib", + sha256 = "b8a1527901774180afc798aeb28c4634bdccf19c4d98e7bdd1ce79d1fe9aaad7", + urls = ["https://github.com/bazelbuild/bazel-skylib/releases/download/1.4.1/bazel-skylib-1.4.1.tar.gz"], +) + +load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace") +bazel_skylib_workspace() + +# Google Absail. +http_archive( + name = "com_google_absl", + sha256 = "3ea49a7d97421b88a8c48a0de16c16048e17725c7ec0f1d3ea2683a2a75adc21", + urls = ["https://github.com/abseil/abseil-cpp/archive/refs/tags/20230125.0.tar.gz"], + strip_prefix="abseil-cpp-20230125.0", +) + +# Google protobuf. +http_archive( + name = "com_google_protobuf", + sha256 = "4eab9b524aa5913c6fffb20b2a8abf5ef7f95a80bc0701f3a6dbb4c607f73460", + urls = ["https://github.com/protocolbuffers/protobuf/releases/download/v21.12/protobuf-cpp-3.21.12.tar.gz"], + strip_prefix="protobuf-3.21.12", +) + +# Google re2 +http_archive( + name = "com_google_re2", + sha256 = "7a9a4824958586980926a300b4717202485c4b4115ac031822e29aa4ef207e48", + urls = ["https://github.com/google/re2/archive/refs/tags/2023-03-01.tar.gz"], + strip_prefix = "re2-2023-03-01" +) + +# ELFIO header based library. +http_archive( + build_file = "BUILD.elfio", + name = "com_github_serge1_elfio", + strip_prefix = "elfio-3.9", + sha256 = "767b269063fc35aba6d361139f830aa91c45dc6b77942f082666876c1aa0be0f", + urls = ["https://github.com/serge1/ELFIO/releases/download/Release_3.9/elfio-3.9.tar.gz"], +) + +# Bazel rules for proto. +http_archive( + name = "rules_proto_grpc", + sha256 = "fb7fc7a3c19a92b2f15ed7c4ffb2983e956625c1436f57a3430b897ba9864059", + strip_prefix = "rules_proto_grpc-4.3.0", + urls = ["https://github.com/rules-proto-grpc/rules_proto_grpc/archive/4.3.0.tar.gz"], +) + +# Google test. +http_archive( + name = "com_google_googletest", + strip_prefix = "googletest-1.13.0", + sha256 = "ad7fdba11ea011c1d925b3289cf4af2c66a352e18d4c7264392fead75e919363", + urls = ["https://github.com/google/googletest/archive/refs/tags/v1.13.0.tar.gz"], +) + +ALL_CONTENT = """\ +filegroup( + name = "all_srcs", + srcs = glob(["**"]), + visibility = ["//visibility:public"], +) +""" + +# Antlr4 c++ runtime. +http_archive( + name = "org_antlr4_cpp_runtime", + build_file = "BUILD.antlr4", + sha256 = "8018c335316e61bb768e5bd4a743a9303070af4e1a8577fa902cd053c17249da", + urls = ["https://www.antlr.org/download/antlr4-cpp-runtime-4.11.1-source.zip"], +) + +# Antlr4 tool (java). +http_file( + name = "org_antlr_tool", + sha256 = "62975e192b4af2622b72b5f0131553ee3cbce97f76dc2a41632dcc55e25473e1", + url = "https://www.antlr.org/download/antlr-4.11.1-complete.jar", +) + +# Additional rules for building non-bazel projects. Antlr4 builds using cmake. +http_archive( + name = "rules_foreign_cc", + sha256 = "2a4d07cd64b0719b39a7c12218a3e507672b82a97b98c6a89d38565894cf7c51", + strip_prefix = "rules_foreign_cc-0.9.0", + url = "https://github.com/bazelbuild/rules_foreign_cc/archive/refs/tags/0.9.0.tar.gz", +) + +# MPACT-Sim repo +git_repository( + name = "mpact-sim", + branch = "main", + remote = "https://mpact.googlesource.com/mpact-sim", +) + +# MPACT-RiscV repo +git_repository( + name = "mpact-riscv", + branch = "main", + remote = "https://mpact.googlesource.com/mpact-riscv", +) + +# Binding to tool targets in mpact-sim. This is required for the macros +# in mpact_sim_isa.bzl to work properly when generating code for the +# decoders. These create the //external:decoder_gen and +# //external:bin_format_gen aliases used in mpact_sim_isa.bzl. +bind( + name = "decoder_gen", + actual = "@mpact-sim//mpact/sim/decoder:decoder_gen", +) + +bind( + name = "bin_format_gen", + actual = "@mpact-sim//mpact/sim/decoder:bin_format_gen", +) + +# Additional rules for licenses +http_archive( + name = "rules_license", + sha256 = "6157e1e68378532d0241ecd15d3c45f6e5cfd98fc10846045509fb2a7cc9e381", + url = "https://github.com/bazelbuild/rules_license/releases/download/0.0.4/rules_license-0.0.4.tar.gz" +) + +load("@rules_foreign_cc//foreign_cc:repositories.bzl", "rules_foreign_cc_dependencies") +rules_foreign_cc_dependencies() + +load("@rules_proto_grpc//:repositories.bzl", "rules_proto_grpc_toolchains", "rules_proto_grpc_repos") +rules_proto_grpc_toolchains() +rules_proto_grpc_repos() + +load("@rules_proto//proto:repositories.bzl", "rules_proto_dependencies", "rules_proto_toolchains") +rules_proto_dependencies() +rules_proto_toolchains() + +load("@rules_license//:deps.bzl", "rules_license_dependencies") +rules_license_dependencies()
diff --git a/other/BUILD b/other/BUILD new file mode 100644 index 0000000..4ed5735 --- /dev/null +++ b/other/BUILD
@@ -0,0 +1,71 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# RiscV sim library for use with codelabs + +package( + default_applicable_licenses = ["//:license"], + default_visibility = ["//visibility:public"], +) + +cc_library( + name = "rv32i_top", + srcs = [ + "rv32i_top.cc", + ], + hdrs = [ + "rv32i_top.h", + ], + deps = [ + "//riscv_full_decoder/solution:riscv32i_decoder", + "//riscv_isa_decoder/solution:riscv32i_isa", + "@com_google_absl//absl/functional:bind_front", + "@com_google_absl//absl/status", + "@com_google_absl//absl/status:statusor", + "@com_google_absl//absl/strings", + "@mpact-riscv//riscv:riscv32_htif_semihost", + "@mpact-riscv//riscv:riscv_breakpoint", + "@mpact-riscv//riscv:riscv_state", + "@mpact-sim//mpact/sim/generic:component", + "@mpact-sim//mpact/sim/generic:core", + "@mpact-sim//mpact/sim/generic:core_debug_interface", + "@mpact-sim//mpact/sim/generic:decode_cache", + "@mpact-sim//mpact/sim/util/memory", + ], +) + +cc_binary( + name = "rv32i_sim", + srcs = [ + "rv32i_sim.cc", + ], + copts = ["-O3"], + args = ["other/hello_rv32i.elf"], + data = [ + "hello_rv32i.elf", + ], + deps = [ + ":rv32i_top", + "@com_google_absl//absl/flags:flag", + "@com_google_absl//absl/flags:parse", + "@com_google_absl//absl/status", + "@com_google_absl//absl/strings", + "@mpact-riscv//riscv:debug_command_shell", + "@mpact-riscv//riscv:riscv32_htif_semihost", + "@mpact-sim//mpact/sim/generic:core", + "@mpact-sim//mpact/sim/proto:component_data_cc_proto", + "@mpact-sim//mpact/sim/util/memory", + "@mpact-sim//mpact/sim/util/program_loader:elf_loader", + ], +)
diff --git a/other/hello_rv32i.elf b/other/hello_rv32i.elf new file mode 100755 index 0000000..c3dbfda --- /dev/null +++ b/other/hello_rv32i.elf Binary files differ
diff --git a/other/rv32i_sim.cc b/other/rv32i_sim.cc new file mode 100644 index 0000000..8584985 --- /dev/null +++ b/other/rv32i_sim.cc
@@ -0,0 +1,172 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include <signal.h> + +#include <functional> +#include <iostream> +#include <memory> +#include <ostream> +#include <string> +#include <vector> + +#include "absl/flags/flag.h" +#include "absl/flags/parse.h" +#include "absl/log/log.h" +#include "absl/log/check.h" +#include "absl/strings/str_cat.h" +#include "mpact/sim/generic/data_buffer.h" +#include "mpact/sim/proto/component_data.pb.h" +#include "mpact/sim/util/memory/memory_watcher.h" +#include "mpact/sim/util/program_loader/elf_program_loader.h" +#include "other/rv32i_top.h" +#include "riscv/debug_command_shell.h" +#include "riscv/riscv32_htif_semihost.h" +#include "src/google/protobuf/text_format.h" + +using ::mpact::sim::proto::ComponentData; +using ::mpact::sim::riscv::RiscV32HtifSemiHost; +using AddressRange = mpact::sim::util::MemoryWatcher::AddressRange; + +// Flags for specifying interactive mode. +ABSL_FLAG(bool, i, false, "Interactive mode"); +ABSL_FLAG(bool, interactive, false, "Interactive mode"); +// Flag for destination directory of proto file. +ABSL_FLAG(std::string, output_dir, "", "Output directory"); + +// Static pointer to the top instance. Used by the control-C handler. +static mpact::sim::codelab::RV32ITop *top = nullptr; + +// Control-c handler to interrupt any running simulation. +static void sim_sigint_handler(int arg) { + if (top != nullptr) { + (void)top->Halt(); + return; + } else { + exit(-1); + } +} + +// Helper function to get the magic semihosting addresses from the loader. +static bool GetMagicAddresses(mpact::sim::util::ElfProgramLoader *loader, + RiscV32HtifSemiHost::SemiHostAddresses *magic) { + auto result = loader->GetSymbol("tohost_ready"); + if (!result.ok()) return false; + magic->tohost_ready = result.value().first; + + result = loader->GetSymbol("tohost"); + if (!result.ok()) return false; + magic->tohost = result.value().first; + + result = loader->GetSymbol("fromhost_ready"); + if (!result.ok()) return false; + magic->fromhost_ready = result.value().first; + + result = loader->GetSymbol("fromhost"); + if (!result.ok()) return false; + magic->fromhost = result.value().first; + + return true; +} + +int main(int argc, char **argv) { + auto arg_vec = absl::ParseCommandLine(argc, argv); + + if (arg_vec.size() > 2) { + std::cerr << "Only a single input file allowed" << std::endl; + return -1; + } + std::string full_file_name = arg_vec[1]; + std::string file_name = + full_file_name.substr(full_file_name.find_last_of('/') + 1); + std::string file_basename = file_name.substr(0, file_name.find_first_of('.')); + + mpact::sim::codelab::RV32ITop rv32i_top("RV32I"); + + // Set up control-c handling. + top = &rv32i_top; + struct sigaction sa; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + sigaddset(&sa.sa_mask, SIGINT); + sa.sa_handler = &sim_sigint_handler; + sigaction(SIGINT, &sa, nullptr); + + // Load the elf segments into memory. + mpact::sim::util::ElfProgramLoader elf_loader(rv32i_top.memory()); + auto load_result = elf_loader.LoadProgram(full_file_name); + if (!load_result.ok()) { + std::cerr << "Error while loading '" << full_file_name + << "': " << load_result.status().message(); + } + + // Initialize the PC to the entry point. + uint32_t entry_point = load_result.value(); + auto pc_write = rv32i_top.WriteRegister("pc", entry_point); + if (!pc_write.ok()) { + std::cerr << "Error writing to pc: " << pc_write.message(); + } + + // Set up semihosting. + RiscV32HtifSemiHost::SemiHostAddresses magic_addresses; + if (GetMagicAddresses(&elf_loader, &magic_addresses)) { + auto status = rv32i_top.SetUpSemiHosting(magic_addresses); + if (!status.ok()) { + std::cerr << "Failed to set up semihosting\n"; + exit(-1); + } + } + + // Determine if this is being run interactively or as a batch job. + bool interactive = absl::GetFlag(FLAGS_i) || absl::GetFlag(FLAGS_interactive); + if (interactive) { + mpact::sim::riscv::DebugCommandShell cmd_shell({{&rv32i_top, &elf_loader}}); + cmd_shell.Run(std::cin, std::cout); + } else { + std::cerr << "Starting simulation\n"; + + auto run_status = rv32i_top.Run(); + if (!run_status.ok()) { + std::cerr << run_status.message() << std::endl; + } + + auto wait_status = rv32i_top.Wait(); + if (!wait_status.ok()) { + std::cerr << wait_status.message() << std::endl; + } + + std::cerr << "Simulation done\n"; + } + + // Export counters. + auto component_proto = std::make_unique<ComponentData>(); + CHECK_OK(rv32i_top.Export(component_proto.get())) << "Failed to export proto"; + std::string proto_file_name; + if (FLAGS_output_dir.CurrentValue().empty()) { + proto_file_name = "./" + file_basename + ".proto"; + } else { + proto_file_name = + FLAGS_output_dir.CurrentValue() + "/" + file_basename + ".proto"; + } + std::fstream proto_file(proto_file_name.c_str(), std::ios_base::out); + std::string serialized; + if (!proto_file.good() || !google::protobuf::TextFormat::PrintToString( + *component_proto.get(), &serialized)) { + LOG(ERROR) << "Failed to write proto to file"; + } else { + proto_file << serialized; + proto_file.close(); + } + +}
diff --git a/other/rv32i_top.cc b/other/rv32i_top.cc new file mode 100644 index 0000000..6574ea5 --- /dev/null +++ b/other/rv32i_top.cc
@@ -0,0 +1,472 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "other/rv32i_top.h" + +#include <algorithm> +#include <cstdint> +#include <cstring> +#include <string> +#include <thread> + +#include "absl/functional/bind_front.h" +#include "absl/log/check.h" +#include "absl/status/status.h" +#include "absl/strings/str_cat.h" +#include "mpact/sim/generic/data_buffer.h" +#include "riscv/riscv32_htif_semihost.h" +#include "riscv/riscv_breakpoint.h" + +namespace mpact { +namespace sim { +namespace codelab { + +using generic::DataBuffer; +using riscv::RiscVXlen; + +constexpr char kRiscV32Name[] = "RiscV"; +constexpr char kRegisterAliases[32][6] = { + "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", "s0", "s1", "a0", + "a1", "a2", "a3", "a4", "a5", "a6", "a7", "s2", "s3", "s4", "s5", + "s6", "s7", "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6"}; + +RV32ITop::RV32ITop(std::string name) + : Component(name), + counter_num_instructions_("num_instructions", 0) { + // Using a single flat memory for this core. + memory_ = new util::FlatDemandMemory(0); + // Creat the simulation state. + state_ = new RiscVState(kRiscV32Name, RiscVXlen::RV32, memory_); + pc_ = state_->GetRegister<RV32Register>(RiscVState::kPcName).first; + // Set up the decoder and decode cache. + rv32_decoder_ = new RiscV32Decoder(state_, memory_); + rv32_decode_cache_ = + generic::DecodeCache::Create({16 * 1024, 2}, rv32_decoder_); + // Register instruction opcode counters. + for (int i = 0; i < static_cast<int>(OpcodeEnum::kPastMaxValue); i++) { + counter_opcode_[i].Initialize(absl::StrCat("num_", kOpcodeNames[i]), 0); + CHECK_OK(AddCounter(&counter_opcode_[i])); + } + // Register instruction counter. + CHECK_OK(AddCounter(&counter_num_instructions_)) + << "Failed to register counter"; + rv_bp_manager_ = new RiscVBreakpointManager( + memory_, + absl::bind_front(&generic::DecodeCache::Invalidate, rv32_decode_cache_)); + // Set the software breakpoint callback. + state_->AddEbreakHandler([this](const Instruction *inst) -> bool { + // If there is a breakpoint, handle it and return true to signal that + // the ebreak has been handled. Otherwise return false. + if ((inst != nullptr) && (HasBreakpoint(inst->address()))) { + RequestHalt(HaltReason::kSoftwareBreakpoint, inst); + return true; + } + return false; + }); + // Make sure the architectural and abi register aliases are added. + for (int i = 0; i < 32; i++) { + std::string reg_name = absl::StrCat(RiscVState::kXregPrefix, i); + (void)state_->AddRegister<RV32Register>(reg_name); + (void)state_->AddRegisterAlias<RV32Register>(reg_name, kRegisterAliases[i]); + } +} + +RV32ITop::~RV32ITop() { + // If the simulator is still running, request a halt (set halted_ to true), + // and wait until the simulator finishes before continuing the destructor. + if (run_status_ == RunStatus::kRunning) { + run_halted_->WaitForNotification(); + delete run_halted_; + run_halted_ = nullptr; + } + + delete rv32_semihost_; + delete rv_bp_manager_; + delete rv32_decode_cache_; + delete rv32_decoder_; + delete state_; + delete watcher_; + delete memory_; +} + +absl::Status RV32ITop::Halt() { + // If it is already halted, just return. + if (run_status_ == RunStatus::kHalted) { + return absl::OkStatus(); + } + // If it is not running, then there's an error. + if (run_status_ != RunStatus::kRunning) { + return absl::FailedPreconditionError("RV32ITop::Halt: Core is not running"); + } + halt_reason_ = HaltReason::kUserRequest; + halted_ = true; + return absl::OkStatus(); +} + +absl::StatusOr<int> RV32ITop::Step(int num) { + if (num <= 0) { + return absl::InvalidArgumentError("Step count must be > 0"); + } + // If the simulator is running, return with an error. + if (run_status_ != RunStatus::kHalted) { + return absl::FailedPreconditionError("RV32ITop::Step: Core must be halted"); + } + run_status_ = RunStatus::kSingleStep; + int count = 0; + halted_ = false; + + // First check to see if the previous halt was due to a breakpoint. If so, + // need to step over the breakpoint. + if (halt_reason_ == HaltReason::kSoftwareBreakpoint) { + auto bp_pc = previous_pc_; + // Disable the breakpoint. Status will show error if there is no breakpoint. + auto status = rv_bp_manager_->DisableBreakpoint(bp_pc); + // Execute the real instruction. + auto prev_inst = rv32_decode_cache_->GetDecodedInstruction(bp_pc); + prev_inst->Execute(nullptr); + counter_opcode_[prev_inst->opcode()].Increment(1); + counter_num_instructions_.Increment(1); + count++; + // Re-enable the breakpoint. + if (status.ok()) { + status = rv_bp_manager_->EnableBreakpoint(bp_pc); + if (!status.ok()) return status; + } + // No longer stopped at breakpoint, so update halt reason. + halt_reason_ = HaltReason::kNone; + } + + // Step the simulator forward until the number of steps have been achieved, or + // there is a halt request. + + DataBuffer *pc_db = pc_->data_buffer(); + uint32_t next_pc = pc_db->Get<uint32_t>(0); + uint32_t pc; + while (count < num) { + pc = next_pc; + auto *inst = rv32_decode_cache_->GetDecodedInstruction(pc); + inst->Execute(nullptr); + count++; + next_pc += inst->size(); + DataBuffer *tmp_db = pc_->data_buffer(); + if (pc_db != tmp_db) { + // PC has been updated by an instruction. + pc_db = tmp_db; + next_pc = pc_db->Get<uint32_t>(0); + } + counter_opcode_[inst->opcode()].Increment(1); + counter_num_instructions_.Increment(1); + if (halted_) break; + } + previous_pc_ = pc; + // Update the pc register, now that it can be read. + pc_db->Set<uint32_t>(0, next_pc); + // If there is no halt request, there is no specific halt reason. + if (!halted_) { + halt_reason_ = HaltReason::kNone; + } + run_status_ = RunStatus::kHalted; + return count; +} + +absl::Status RV32ITop::Run() { + // Verify that the core isn't running already. + if (run_status_ == RunStatus::kRunning) { + return absl::FailedPreconditionError( + "RV32ITop::Run: core is already running"); + } + + // First check to see if the previous halt was due to a breakpoint. If so, + // need to step over the breakpoint. + if (halt_reason_ == HaltReason::kSoftwareBreakpoint) { + auto bp_pc = previous_pc_; + // Disable the breakpoint. + auto status = rv_bp_manager_->DisableBreakpoint(bp_pc); + // Execute the real instruction. + auto prev_inst = rv32_decode_cache_->GetDecodedInstruction(bp_pc); + prev_inst->Execute(nullptr); + counter_opcode_[prev_inst->opcode()].Increment(1); + counter_num_instructions_.Increment(1); + // Re-enable the breakpoint. + if (status.ok()) { + status = rv_bp_manager_->EnableBreakpoint(bp_pc); + if (!status.ok()) return status; + } + // No longer stopped at breakpoint, so update halt reason. + halt_reason_ = HaltReason::kNone; + } + + run_status_ = RunStatus::kRunning; + halted_ = false; + + // The simulator is now run in a separate thread so as to allow a user + // interface to continue operating. Allocate a new run_halted_ Notification + // object, as they are single use only. + run_halted_ = new absl::Notification(); + + // The thread is detached so it executes without having to be joined. + std::thread([this]() { + DataBuffer *pc_db = pc_->data_buffer(); + uint32_t next_pc = pc_db->Get<uint32_t>(0); + uint32_t pc; + while (!halted_) { + pc = next_pc; + auto *inst = rv32_decode_cache_->GetDecodedInstruction(pc); + inst->Execute(nullptr); + next_pc += inst->size(); + DataBuffer *tmp_db = pc_->data_buffer(); + if (pc_db != tmp_db) { + // PC has been updated by an instruction. + pc_db = tmp_db; + next_pc = pc_db->Get<uint32_t>(0); + } + counter_opcode_[inst->opcode()].Increment(1); + counter_num_instructions_.Increment(1); + } + previous_pc_ = pc; + // Update the pc register, now that it can be read. + pc_db->Set<uint32_t>(0, next_pc); + run_status_ = RunStatus::kHalted; + // Notify that the run has completed. + run_halted_->Notify(); + }).detach(); + return absl::OkStatus(); +} + +absl::Status RV32ITop::Wait() { + // If the simulator isn't running, then just return. + if (run_status_ != RunStatus::kRunning) { + delete run_halted_; + run_halted_ = nullptr; + return absl::OkStatus(); + } + + // Wait for the simulator to finish - i.e., notification on run_halted_ + run_halted_->WaitForNotification(); + // Now delete the notification object - it is single use only. + delete run_halted_; + run_halted_ = nullptr; + return absl::OkStatus(); +} + +absl::StatusOr<RV32ITop::RunStatus> RV32ITop::GetRunStatus() { + return run_status_; +} + +absl::StatusOr<RV32ITop::HaltReason> RV32ITop::GetLastHaltReason() { + return halt_reason_; +} + +absl::StatusOr<uint64_t> RV32ITop::ReadRegister(const std::string &name) { + // The registers aren't protected by a mutex, so let's not read them while + // the simulator is running. + if (run_status_ != RunStatus::kHalted) { + return absl::FailedPreconditionError("ReadRegister: Core must be halted"); + } + auto iter = state_->registers()->find(name); + // Was the register found? + if (iter == state_->registers()->end()) + return absl::NotFoundError(absl::StrCat("Register '", name, "' not found")); + + // If requesting PC and we're stopped at a software breakpoint, the next + // instruction to be executed is at the address of the software breakpoint, so + // return that address. + if ((name == "pc") && (halt_reason_ == HaltReason::kSoftwareBreakpoint)) { + return previous_pc_; + } + + auto *db = (iter->second)->data_buffer(); + uint64_t value; + switch (db->size<uint8_t>()) { + case 1: + value = static_cast<uint64_t>(db->Get<uint8_t>(0)); + return value; + case 2: + value = static_cast<uint64_t>(db->Get<uint16_t>(0)); + return value; + case 4: + value = static_cast<uint64_t>(db->Get<uint32_t>(0)); + return value; + case 8: + value = static_cast<uint64_t>(db->Get<uint64_t>(0)); + return value; + default: + return absl::InternalError("Register size is not 1, 2, 4, or 8 bytes"); + } +} + +absl::Status RV32ITop::WriteRegister(const std::string &name, uint64_t value) { + // The registers aren't protected by a mutex, so let's not read them while + // the simulator is running. + if (run_status_ != RunStatus::kHalted) { + return absl::FailedPreconditionError("WriteRegister: Core must be halted"); + } + auto iter = state_->registers()->find(name); + // Was the register found? + if (iter == state_->registers()->end()) + return absl::NotFoundError(absl::StrCat("Register '", name, "' not found")); + + // If stopped at a software breakpoing and the pc is changed, change the + // halt reason, since the next instruction won't be were we stopped. + if ((name == "pc") && (halt_reason_ == HaltReason::kSoftwareBreakpoint)) { + halt_reason_ = HaltReason::kNone; + } + + auto *db = (iter->second)->data_buffer(); + switch (db->size<uint8_t>()) { + case 1: + db->Set<uint8_t>(0, static_cast<uint8_t>(value)); + break; + case 2: + db->Set<uint16_t>(0, static_cast<uint16_t>(value)); + break; + case 4: + db->Set<uint32_t>(0, static_cast<uint32_t>(value)); + break; + case 8: + db->Set<uint64_t>(0, static_cast<uint64_t>(value)); + break; + default: + return absl::InternalError("Register size is not 1, 2, 4, or 8 bytes"); + } + return absl::OkStatus(); +} + +absl::StatusOr<size_t> RV32ITop::ReadMemory(uint64_t address, void *buffer, + size_t length) { + if (run_status_ != RunStatus::kHalted) { + return absl::FailedPreconditionError("ReadMemory: Core must be halted"); + } + auto *db = db_factory_.Allocate(length); + // Load bypassing any watch points/semihosting. + state_->memory()->Load(address, db, nullptr, nullptr); + std::memcpy(buffer, db->raw_ptr(), length); + db->DecRef(); + return length; +} + +absl::StatusOr<size_t> RV32ITop::WriteMemory(uint64_t address, + const void *buffer, + size_t length) { + if (run_status_ != RunStatus::kHalted) { + return absl::FailedPreconditionError("WriteMemory: Core must be halted"); + } + auto *db = db_factory_.Allocate(length); + std::memcpy(db->raw_ptr(), buffer, length); + // Store bypassing any watch points/semihosting. + state_->memory()->Store(address, db); + db->DecRef(); + return length; +} + +bool RV32ITop::HasBreakpoint(uint64_t address) { + return rv_bp_manager_->HasBreakpoint(address); +} + +absl::Status RV32ITop::SetSwBreakpoint(uint64_t address) { + // Don't try if the simulator is running. + if (run_status_ != RunStatus::kHalted) { + return absl::FailedPreconditionError( + "SetSwBreakpoint: Core must be halted"); + } + // If there is no breakpoint manager, return an error. + if (rv_bp_manager_ == nullptr) { + return absl::InternalError("Breakpoints are not enabled"); + } + // Try setting the breakpoint. + return rv_bp_manager_->SetBreakpoint(address); +} + +absl::Status RV32ITop::ClearSwBreakpoint(uint64_t address) { + // Don't try if the simulator is running. + if (run_status_ != RunStatus::kHalted) { + return absl::FailedPreconditionError( + "ClearSwBreakpoing: Core must be halted"); + } + if (rv_bp_manager_ == nullptr) { + return absl::InternalError("Breakpoints are not enabled"); + } + return rv_bp_manager_->ClearBreakpoint(address); +} + +absl::Status RV32ITop::ClearAllSwBreakpoints() { + // Don't try if the simulator is running. + if (run_status_ != RunStatus::kHalted) { + return absl::FailedPreconditionError( + "ClearAllSwBreakpoints: Core must be halted"); + } + if (rv_bp_manager_ == nullptr) { + return absl::InternalError("Breakpoints are not enabled"); + } + rv_bp_manager_->ClearAllBreakpoints(); + return absl::OkStatus(); +} + +absl::StatusOr<Instruction *> RV32ITop::GetInstruction(uint64_t address) { + auto inst = rv32_decode_cache_->GetDecodedInstruction(address); + return inst; +} + +absl::StatusOr<std::string> RV32ITop::GetDisassembly(uint64_t address) { + // Don't try if the simulator is running. + if (run_status_ != RunStatus::kHalted) { + return absl::FailedPreconditionError("GetDissasembly: Core must be halted"); + } + + Instruction *inst; + // If requesting the disassembly for an instruction at a breakpoint, return + // that of the original instruction instead. + if (rv_bp_manager_->IsBreakpoint(address)) { + auto bp_pc = address; + // Disable the breakpoint. + auto status = rv_bp_manager_->DisableBreakpoint(bp_pc); + if (!status.ok()) return status; + // Get the real instruction. + inst = rv32_decode_cache_->GetDecodedInstruction(bp_pc); + // Re-enable the breakpoint. + status = rv_bp_manager_->EnableBreakpoint(bp_pc); + if (!status.ok()) return status; + } else { + // If not at the breakpoint, or requesting a different instruction, + inst = rv32_decode_cache_->GetDecodedInstruction(address); + } + return inst != nullptr ? inst->AsString() : "Invalid instruction"; +} + +absl::Status RV32ITop::SetUpSemiHosting(const SemiHostAddresses &magic) { + // Don't try if the simulator is running. + if (run_status_ != RunStatus::kHalted) { + return absl::FailedPreconditionError( + "SetupSemihosting: Core must be halted"); + } + watcher_ = new util::MemoryWatcher(memory_); + rv32_semihost_ = new RiscV32HtifSemiHost( + watcher_, memory_, magic, + [this]() { RequestHalt(HaltReason::kSemihostHaltRequest, nullptr); }, + [this](std::string) { + RequestHalt(HaltReason::kSemihostHaltRequest, nullptr); + }); + state_->set_memory(watcher_); + return absl::OkStatus(); +} + +void RV32ITop::RequestHalt(HaltReason halt_reason, const Instruction *inst) { + // First set the halt_reason_, then the half flag. + halt_reason_ = halt_reason; + halted_ = true; +} + +} // namespace codelab +} // namespace sim +} // namespace mpact
diff --git a/other/rv32i_top.h b/other/rv32i_top.h new file mode 100644 index 0000000..8db0dbc --- /dev/null +++ b/other/rv32i_top.h
@@ -0,0 +1,129 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MPACT_SIM_CODELABS_OTHER_RV32I_TOP_H_ +#define MPACT_SIM_CODELABS_OTHER_RV32I_TOP_H_ + +#include <string> + +#include "absl/status/status.h" +#include "absl/synchronization/notification.h" +#include "mpact/sim/generic/component.h" +#include "mpact/sim/generic/core_debug_interface.h" +#include "mpact/sim/generic/decode_cache.h" +#include "mpact/sim/util/memory/flat_demand_memory.h" +#include "mpact/sim/util/memory/memory_interface.h" +#include "mpact/sim/util/memory/memory_watcher.h" +#include "riscv/riscv32_htif_semihost.h" +#include "riscv/riscv_breakpoint.h" +#include "riscv/riscv_register.h" +#include "riscv/riscv_state.h" +#include "riscv_full_decoder/solution/riscv32_decoder.h" +#include "riscv_isa_decoder/solution/riscv32i_enums.h" + +namespace mpact { +namespace sim { +namespace codelab { + +using riscv::RiscV32HtifSemiHost; +using riscv::RiscVBreakpointManager; +using riscv::RiscVState; +using riscv::RV32Register; + +// Top level class for the RiscV32G simulator. This is the main interface for +// interacting and controlling execution of programs running on the simulator. +// This class brings together the decoder, the architecture state, and control. +class RV32ITop : public generic::Component, public generic::CoreDebugInterface { + public: + using RunStatus = generic::CoreDebugInterface::RunStatus; + using HaltReason = generic::CoreDebugInterface::HaltReason; + using SemiHostAddresses = RiscV32HtifSemiHost::SemiHostAddresses; + + explicit RV32ITop(std::string name); + ~RV32ITop() override; + + // Methods inherited from CoreDebugInterface. + absl::Status Halt() override; + absl::StatusOr<int> Step(int num) override; + absl::Status Run() override; + absl::Status Wait() override; + + absl::StatusOr<RunStatus> GetRunStatus() override; + absl::StatusOr<HaltReason> GetLastHaltReason() override; + + absl::StatusOr<uint64_t> ReadRegister(const std::string &name) override; + absl::Status WriteRegister(const std::string &name, uint64_t value) override; + + // Read and Write memory methods bypass any semihosting. + absl::StatusOr<size_t> ReadMemory(uint64_t address, void *buf, + size_t length) override; + absl::StatusOr<size_t> WriteMemory(uint64_t address, const void *buf, + size_t length) override; + + bool HasBreakpoint(uint64_t address) override; + absl::Status SetSwBreakpoint(uint64_t address) override; + absl::Status ClearSwBreakpoint(uint64_t address) override; + absl::Status ClearAllSwBreakpoints() override; + + absl::StatusOr<Instruction *>GetInstruction(uint64_t address) override; + + absl::StatusOr<std::string> GetDisassembly(uint64_t address) override; + + // Set up semihosting with the given magic addresses. + absl::Status SetUpSemiHosting(const SemiHostAddresses &magic); + + // Accessors. + RiscVState *state() const { return state_; } + util::MemoryInterface *memory() const { return memory_; } + + private: + // Called when a halt is requested. + void RequestHalt(HaltReason halt_reason, const Instruction *inst); + + uint32_t previous_pc_; + // The DB factory is used to manage data buffers for memory read/writes. + generic::DataBufferFactory db_factory_; + // Current status and last halt reasons. + RunStatus run_status_ = RunStatus::kHalted; + HaltReason halt_reason_ = HaltReason::kNone; + // Halting flag. This is set to true when execution must halt. + bool halted_ = false; + absl::Notification *run_halted_ = nullptr; + // The local RiscV32 state. + RiscVState *state_; + // Semihosting class. + RiscV32HtifSemiHost *rv32_semihost_ = nullptr; + // Breakpoint manager. + RiscVBreakpointManager *rv_bp_manager_ = nullptr; + // The pc register instance. + RV32Register *pc_; + // RiscV32 decoder instance. + RiscV32Decoder *rv32_decoder_ = nullptr; + // Decode cache, memory and memory watcher. + generic::DecodeCache *rv32_decode_cache_ = nullptr; + util::FlatDemandMemory *memory_ = nullptr; + util::MemoryWatcher *watcher_ = nullptr; + // Counter for the number of instructions simulated. + generic::SimpleCounter<uint64_t> + counter_opcode_[static_cast<int>(OpcodeEnum::kPastMaxValue)]; + generic::SimpleCounter<uint64_t> counter_num_instructions_; +}; + +} // namespace codelab +} // namespace sim +} // namespace mpact + +#endif // MPACT_SIM_CODELABS_OTHER_RV32I_TOP_H_
diff --git a/riscv_bin_decoder/BUILD b/riscv_bin_decoder/BUILD new file mode 100644 index 0000000..7be1267 --- /dev/null +++ b/riscv_bin_decoder/BUILD
@@ -0,0 +1,32 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Build file for the bin_decoder part of the RiscV instruction decoder codelab. + +load("@mpact-sim//mpact/sim/decoder:mpact_sim_isa.bzl", "mpact_bin_fmt_decoder") + +package( + default_applicable_licenses = ["//:license"], + default_visibility = ["//visibility:public"], +) + +mpact_bin_fmt_decoder( + name = "riscv32i_bin_fmt", + src = "riscv32i.bin_fmt", + decoder_name = "RiscV32I", + includes = [], + deps = [ + "//riscv_isa_decoder/solution:riscv32i_isa", + ], +)
diff --git a/riscv_bin_decoder/riscv32i.bin_fmt b/riscv_bin_decoder/riscv32i.bin_fmt new file mode 100644 index 0000000..5ebbfd0 --- /dev/null +++ b/riscv_bin_decoder/riscv32i.bin_fmt
@@ -0,0 +1,82 @@ +// This declares the decoder. +decoder RiscV32I { + // The namespace in which code will be generated. + namespace mpact::sim::codelab; + // The name (including any namespace qualifiers) of the opcode enum type. + opcode_enum = "OpcodeEnum"; + // Include files specific to this decoder. + includes { + #include "riscv_isa_decoder/solution/riscv32i_decoder.h" + } + // Instruction groups for which to generate decode functions. + RiscVInst32; +}; + +// The generic RiscV 32 bit instruction format. +format Inst32Format[32] { + fields: + unsigned bits[25]; + unsigned opcode[7]; +}; + +// Exercise 2 format. +// End of Exercise 2 format. + +// RiscV 32 bit instruction format used by a number of instructions +// needing a 12 bit immediate, including CSR instructions. +format IType[32] : Inst32Format { + fields: + signed imm12[12]; + unsigned rs1[5]; + unsigned func3[3]; + unsigned rd[5]; + unsigned opcode[7]; +}; + +// Exercise 3 format. +// End of Exercise 3 format. + +// Exercise 4 formats. +// End of Exercise 4 formats. + +// Exercise 5 format. +// End of Exercise 5 format. + +// Exercise 6 format. +// End of Exercise 6 format. + +// RiscV instruction format used by fence instructions. +format Fence[32] : Inst32Format { + fields: + unsigned fm[4]; + unsigned pred[4]; + unsigned succ[4]; + unsigned rs1[5]; + unsigned func3[3]; + unsigned rd[5]; + unsigned opcode[7]; +}; + +// This defines the RiscVInst32 instruction group which defines the encoding +// of the RiscV instructions we care about. +instruction group RiscVInst32[32] : Inst32Format { + // Exercise 2 instructions. + // End Exercise 2 instructions. + + // Exercise 3 instructions. + // End of Exercise 3 instructions. + + // Exercise 4 instructions. + // End of Exercise 4 instructions. + + // Exercise 5 instructions. + // End of Exercise 5 instructions. + + // Exercise 6 instructions. + // End of Exercise 6 instructions. + + fence : Fence : func3 == 0b000, opcode == 0b000'1111; + csrs : IType : func3 == 0b010, rs1 != 0, opcode == 0b111'0011; + csrw_nr : IType : func3 == 0b001, rd == 0, opcode == 0b111'0011; + csrs_nw : IType : func3 == 0b010, rs1 == 0, opcode == 0b111'0011; +};
diff --git a/riscv_bin_decoder/solution/BUILD b/riscv_bin_decoder/solution/BUILD new file mode 100644 index 0000000..f7b21a4 --- /dev/null +++ b/riscv_bin_decoder/solution/BUILD
@@ -0,0 +1,32 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Build file for the RiscV binary decoder codelab solution. + +load("@mpact-sim//mpact/sim/decoder:mpact_sim_isa.bzl", "mpact_bin_fmt_decoder") + +package( + default_applicable_licenses = ["//:license"], + default_visibility = ["//visibility:public"], +) + +mpact_bin_fmt_decoder( + name = "riscv32i_bin_fmt", + src = "riscv32i.bin_fmt", + decoder_name = "RiscV32I", + includes = [], + deps = [ + "//riscv_isa_decoder/solution:riscv32i_isa", + ], +)
diff --git a/riscv_bin_decoder/solution/riscv32i.bin_fmt b/riscv_bin_decoder/solution/riscv32i.bin_fmt new file mode 100644 index 0000000..cc51378 --- /dev/null +++ b/riscv_bin_decoder/solution/riscv32i.bin_fmt
@@ -0,0 +1,168 @@ +// This declares the decoder. +decoder RiscV32I { + // The namespace in which code will be generated. + namespace mpact::sim::codelab; + // The name (including any namespace qualifiers) of the opcode enum type. + opcode_enum = "OpcodeEnum"; + // Include files specific to this decoder. + includes { + #include "riscv_isa_decoder/solution/riscv32i_decoder.h" + } + // Instruction groups for which to generate decode functions. + RiscVInst32; +}; + +// The generic RiscV 32 bit instruction format. +format Inst32Format[32] { + fields: + unsigned bits[25]; + unsigned opcode[7]; +}; + +// Exercise 2 format. +format RType[32] : Inst32Format { + fields: + unsigned func7[7]; + unsigned rs2[5]; + unsigned rs1[5]; + unsigned func3[3]; + unsigned rd[5]; + unsigned opcode[7]; + overlays: + unsigned uimm5[5] = rs2; // Exercise 3. +}; +// End of Exercise 2 format. + +// RiscV 32 bit instruction format used by a number of instructions +// needing a 12 bit immediate, including CSR instructions. +format IType[32] : Inst32Format { + fields: + signed imm12[12]; + unsigned rs1[5]; + unsigned func3[3]; + unsigned rd[5]; + unsigned opcode[7]; +}; + +// Exercise 3 format. +format UType[32] : Inst32Format { + fields: + unsigned uimm20[20]; + unsigned rd[5]; + unsigned opcode[7]; + overlays: + unsigned uimm32[32] = uimm20, 0b0000'0000'0000; +}; +// End of Exercise 3 format. + +// Exercise 4 formats. +format BType[32] : Inst32Format { + fields: + unsigned imm7[7]; + unsigned rs2[5]; + unsigned rs1[5]; + unsigned func3[3]; + unsigned imm5[5]; + unsigned opcode[7]; + overlays: + signed b_imm[13] = imm7[6], imm5[0], imm7[5..0], imm5[4..1], 0b0; +}; + +format JType[32] : Inst32Format { + fields: + unsigned imm20[20]; + unsigned rd[5]; + unsigned opcode[7]; + overlays: + signed j_imm[21] = imm20[19, 7..0, 8, 18..9], 0b0; +}; +// End of Exercise 4 formats. + +// Exercise 5 format. +format SType[32] : Inst32Format { + fields: + unsigned imm7[7]; + unsigned rs2[5]; + unsigned rs1[5]; + unsigned func3[3]; + unsigned imm5[5]; + unsigned opcode[7]; + overlays: + signed s_imm[12] = imm7, imm5; +}; +// End of Exercise 5 format. + +// There is no Exercise 6 format. + +// RiscV instruction format used by fence instructions. +format Fence[32] : Inst32Format { + fields: + unsigned fm[4]; + unsigned pred[4]; + unsigned succ[4]; + unsigned rs1[5]; + unsigned func3[3]; + unsigned rd[5]; + unsigned opcode[7]; +}; + +// This defines the RiscVInst32 instruction group which defines the encoding +// of the RiscV instructions we care about. +instruction group RiscVInst32[32] : Inst32Format { + // Exercise 2 instructions. + add : RType : func7 == 0b000'0000, func3 == 0b000, opcode == 0b011'0011; + and : RType : func7 == 0b000'0000, func3 == 0b111, opcode == 0b011'0011; + or : RType : func7 == 0b000'0000, func3 == 0b110, opcode == 0b011'0011; + sll : RType : func7 == 0b000'0000, func3 == 0b001, opcode == 0b011'0011; + sltu : RType : func7 == 0b000'0000, func3 == 0b011, opcode == 0b011'0011; + sub : RType : func7 == 0b010'0000, func3 == 0b000, opcode == 0b011'0011; + xor : RType : func7 == 0b000'0000, func3 == 0b100, opcode == 0b011'0011; + // End Exercise 2 instructions. + + // Exercise 3 instructions. + addi : IType : func3 == 0b000, opcode == 0b001'0011; + andi : IType : func3 == 0b111, opcode == 0b001'0011; + ori : IType : func3 == 0b110, opcode == 0b001'0011; + xori : IType : func3 == 0b100, opcode == 0b001'0011; + + slli : RType : func7 == 0b000'0000, func3 == 0b001, opcode == 0b001'0011; + srai : RType : func7 == 0b010'0000, func3 == 0b101, opcode == 0b001'0011; + srli : RType : func7 == 0b000'0000, func3 == 0b101, opcode == 0b001'0011; + + auipc : UType : opcode == 0b001'0111; + lui : UType : opcode == 0b011'0111; + // End Exercise 3 instructions. + + // Exercise 4 instructions. + beq : BType : opcode == 0b110'0011, func3 == 0b000; + bge : BType : opcode == 0b110'0011, func3 == 0b101; + bgeu : BType : opcode == 0b110'0011, func3 == 0b111; + blt : BType : opcode == 0b110'0011, func3 == 0b100; + bltu : BType : opcode == 0b110'0011, func3 == 0b110; + bne : BType : opcode == 0b110'0011, func3 == 0b001; + + jal : JType : opcode == 0b110'1111; + + jalr : IType : opcode == 0b110'0111, func3 == 0b000; + // End of Exercise 4 instructions. + + // Exercise 5 instructions. + sb : SType : opcode == 0b010'0011, func3 == 0b000; + sh : SType : opcode == 0b010'0011, func3 == 0b001; + sw : SType : opcode == 0b010'0011, func3 == 0b010; + // End of Exercise 5 instructions. + + // Exercise 6 instructions. + lb : IType : opcode == 0b000'0011, func3 == 0b000; + lbu : IType : opcode == 0b000'0011, func3 == 0b100; + lh : IType : opcode == 0b000'0011, func3 == 0b001; + lhu : IType : opcode == 0b000'0011, func3 == 0b101; + lw : IType : opcode == 0b000'0011, func3 == 0b010; + // End of Exercise 6 instructions. + + fence : Fence : func3 == 0b000, opcode == 0b000'1111; + ebreak : Inst32Format : bits == 0b0000'0000'0001'00000'000'00000, opcode == 0b111'0011; + csrs : IType : func3 == 0b010, rs1 != 0, opcode == 0b111'0011; + csrw_nr : IType : func3 == 0b001, rd == 0, opcode == 0b111'0011; + csrs_nw : IType : func3 == 0b010, rs1 == 0, opcode == 0b111'0011; +};
diff --git a/riscv_full_decoder/BUILD b/riscv_full_decoder/BUILD new file mode 100644 index 0000000..eb61ee6 --- /dev/null +++ b/riscv_full_decoder/BUILD
@@ -0,0 +1,48 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# riscv_full_decoder codelab project + +package( + default_applicable_licenses = ["//:license"], + default_visibility = ["//visibility:public"], +) + +cc_library( + name = "riscv32i_decoder", + srcs = [ + "riscv32_decoder.cc", + "riscv32i_encoding.cc", + ], + hdrs = [ + "riscv32_decoder.h", + "riscv32i_encoding.h", + ], + deps = [ + "//riscv_bin_decoder/solution:riscv32i_bin_fmt", + "//riscv_isa_decoder/solution:riscv32i_isa", + "//riscv_semantic_functions/solution:riscv32i", + "@mpact-riscv//riscv:riscv_state", + "@mpact-sim//mpact/sim/generic:arch_state", + "@mpact-sim//mpact/sim/generic:core", + "@mpact-sim//mpact/sim/generic:instruction", + "@mpact-sim//mpact/sim/generic:program_error", + "@mpact-sim//mpact/sim/util/memory", + "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/functional:any_invocable", + "@com_google_absl//absl/functional:bind_front", + "@com_google_absl//absl/memory", + "@com_google_absl//absl/strings", + ], +)
diff --git a/riscv_full_decoder/riscv32_decoder.cc b/riscv_full_decoder/riscv32_decoder.cc new file mode 100644 index 0000000..27e3532 --- /dev/null +++ b/riscv_full_decoder/riscv32_decoder.cc
@@ -0,0 +1,38 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "riscv_full_decoder/riscv32_decoder.h" + +using ::mpact::sim::generic::Instruction; +using ::mpact::sim::riscv::RiscVState; +using ::mpact::sim::util::MemoryInterface; + +namespace mpact { +namespace sim { +namespace codelab { + +// Exercise 1 - Step 3. + +// Constructor. +// RiscV32Decoder::RiscV32Decoder(RiscVState *state, MemoryInterface *memory) {} + +// Destructor. +// RiscV32Decoder::~RiscV32Decoder() {} + +// DecodeInstruction method. +// Instruction *RiscV32Decoder::DecodeInstruction(uint64_t address) {} + +} // namespace codelab +} // namespace sim +} // namespace mpact
diff --git a/riscv_full_decoder/riscv32_decoder.h b/riscv_full_decoder/riscv32_decoder.h new file mode 100644 index 0000000..410378c --- /dev/null +++ b/riscv_full_decoder/riscv32_decoder.h
@@ -0,0 +1,47 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MPACT_SIM_CODELABS_FULL_DECODER_RISCV32_DECODER_H_ +#define MPACT_SIM_CODELABS_FULL_DECODER_RISCV32_DECODER_H_ + +#include <memory> + +#include "mpact/sim/generic/arch_state.h" +#include "mpact/sim/generic/decoder_interface.h" +#include "mpact/sim/generic/instruction.h" +#include "mpact/sim/generic/program_error.h" +#include "mpact/sim/util/memory/memory_interface.h" +#include "riscv/riscv_state.h" +#include "riscv_full_decoder/riscv32i_encoding.h" +#include "riscv_isa_decoder/solution/riscv32i_decoder.h" + +namespace mpact { +namespace sim { +namespace codelab { + +using riscv::RiscVState; + +// Exercise 1 - step 1. Fill in the factory class definition. +class RiscV32IsaFactory; + +// Exercise 1 - step 2. Fill in the decoder class definition. +class RiscV32Decoder; + +} // namespace codelab +} // namespace sim +} // namespace mpact + +#endif // MPACT_SIM_CODELABS_FULL_DECODER_RISCV32_DECODER_H_
diff --git a/riscv_full_decoder/riscv32i_encoding.cc b/riscv_full_decoder/riscv32i_encoding.cc new file mode 100644 index 0000000..1ae6a37 --- /dev/null +++ b/riscv_full_decoder/riscv32i_encoding.cc
@@ -0,0 +1,42 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "riscv_full_decoder/riscv32i_encoding.h" + +#include <string> + +#include "riscv_bin_decoder/solution/riscv32i_bin_decoder.h" +#include "mpact/sim/generic/devnull_operand.h" +#include "mpact/sim/generic/immediate_operand.h" +#include "mpact/sim/generic/literal_operand.h" +#include "mpact/sim/generic/operand_interface.h" +#include "riscv/riscv_register.h" +#include "riscv/riscv_state.h" + +namespace mpact { +namespace sim { +namespace codelab { + +using riscv::RiscVState; +using riscv::RV32Register; + +using generic::DevNullOperand; +using generic::ImmediateOperand; +using generic::IntLiteralOperand; + +// Exercise 2. + +} // namespace codelab +} // namespace sim +} // namespace mpact
diff --git a/riscv_full_decoder/riscv32i_encoding.h b/riscv_full_decoder/riscv32i_encoding.h new file mode 100644 index 0000000..8d00498 --- /dev/null +++ b/riscv_full_decoder/riscv32i_encoding.h
@@ -0,0 +1,43 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MPACT_SIM_CODELABS_FULL_DECODER_RISCV32I_ENCODING_H_ +#define MPACT_SIM_CODELABS_FULL_DECODER_RISCV32I_ENCODING_H_ + +#include <functional> +#include <string> + +#include "absl/functional/any_invocable.h" +#include "mpact/sim/generic/operand_interface.h" +#include "riscv/riscv_state.h" +#include "riscv_isa_decoder/solution/riscv32i_decoder.h" +#include "riscv_isa_decoder/solution/riscv32i_enums.h" + +namespace mpact { +namespace sim { +namespace codelab { + +using ::mpact::sim::generic::DestinationOperandInterface; +using ::mpact::sim::generic::PredicateOperandInterface; +using ::mpact::sim::generic::SourceOperandInterface; + +// Exercise 2. + +} // namespace codelab +} // namespace sim +} // namespace mpact + +#endif // MPACT_SIM_CODELABS_FULL_DECODER_RISCV32I_ENCODING_H_
diff --git a/riscv_full_decoder/solution/BUILD b/riscv_full_decoder/solution/BUILD new file mode 100644 index 0000000..cca8c97 --- /dev/null +++ b/riscv_full_decoder/solution/BUILD
@@ -0,0 +1,48 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# riscv_full_decoder codelab solution project + +package( + default_applicable_licenses = ["//:license"], + default_visibility = ["//visibility:public"], +) + +cc_library( + name = "riscv32i_decoder", + srcs = [ + "riscv32_decoder.cc", + "riscv32i_encoding.cc", + ], + hdrs = [ + "riscv32_decoder.h", + "riscv32i_encoding.h", + ], + deps = [ + "//riscv_bin_decoder/solution:riscv32i_bin_fmt", + "//riscv_isa_decoder/solution:riscv32i_isa", + "//riscv_semantic_functions/solution:riscv32i", + "@com_google_absl//absl/container:flat_hash_map", + "@com_google_absl//absl/functional:any_invocable", + "@com_google_absl//absl/functional:bind_front", + "@com_google_absl//absl/memory", + "@com_google_absl//absl/strings", + "@mpact-riscv//riscv:riscv_state", + "@mpact-sim//mpact/sim/generic:arch_state", + "@mpact-sim//mpact/sim/generic:core", + "@mpact-sim//mpact/sim/generic:instruction", + "@mpact-sim//mpact/sim/generic:program_error", + "@mpact-sim//mpact/sim/util/memory", + ], +)
diff --git a/riscv_full_decoder/solution/riscv32_decoder.cc b/riscv_full_decoder/solution/riscv32_decoder.cc new file mode 100644 index 0000000..eef571e --- /dev/null +++ b/riscv_full_decoder/solution/riscv32_decoder.cc
@@ -0,0 +1,57 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "riscv_full_decoder/solution/riscv32_decoder.h" + +namespace mpact { +namespace sim { +namespace codelab { + +using ::mpact::sim::riscv::RiscVState; +using ::mpact::sim::util::MemoryInterface; + +RiscV32Decoder::RiscV32Decoder(RiscVState *state, MemoryInterface *memory) + : state_(state), memory_(memory) { + // Allocate the isa factory class, the top level isa decoder instance, and + // the encoding parser. + riscv_isa_factory_ = new RiscV32IsaFactory(); + riscv_isa_ = new RiscV32IInstructionSet(state, riscv_isa_factory_); + riscv_encoding_ = new RiscV32IEncoding(state); + // Need a data buffer to load instructions from memory. Allocate a single + // buffer that can be reused for each instruction word. + inst_db_ = state_->db_factory()->Allocate<uint32_t>(1); +} + +RiscV32Decoder::~RiscV32Decoder() { + inst_db_->DecRef(); + delete riscv_isa_; + delete riscv_isa_factory_; + delete riscv_encoding_; +} + +generic::Instruction *RiscV32Decoder::DecodeInstruction(uint64_t address) { + // Read the instruction word from memory and parse it in the encoding parser. + memory_->Load(address, inst_db_, nullptr, nullptr); + uint32_t iword = inst_db_->Get<uint32_t>(0); + riscv_encoding_->ParseInstruction(iword); + + // Call the isa decoder to obtain a new instruction object for the instruction + // word that was parsed above. + auto *instruction = riscv_isa_->Decode(address, riscv_encoding_); + return instruction; +} + +} // namespace codelab +} // namespace sim +} // namespace mpact
diff --git a/riscv_full_decoder/solution/riscv32_decoder.h b/riscv_full_decoder/solution/riscv32_decoder.h new file mode 100644 index 0000000..ccae230 --- /dev/null +++ b/riscv_full_decoder/solution/riscv32_decoder.h
@@ -0,0 +1,73 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MPACT_SIM_CODELABS_RISCV_FULL_DECODER_SOLUTION_RISCV32_DECODER_H_ +#define MPACT_SIM_CODELABS_RISCV_FULL_DECODER_SOLUTION_RISCV32_DECODER_H_ + +#include <memory> + +#include "mpact/sim/generic/arch_state.h" +#include "mpact/sim/generic/decoder_interface.h" +#include "mpact/sim/generic/instruction.h" +#include "mpact/sim/util/memory/memory_interface.h" +#include "riscv/riscv_state.h" +#include "riscv_full_decoder/solution/riscv32i_encoding.h" +#include "riscv_isa_decoder/solution/riscv32i_decoder.h" + +namespace mpact { +namespace sim { +namespace codelab { + +// This is the factory class needed by the generated decoder. It is responsible +// for creating the decoder for each slot instance. Since the riscv architecture +// only has a single slot, it's a pretty simple class. +class RiscV32IsaFactory : public RiscV32IInstructionSetFactory { + public: + std::unique_ptr<Riscv32Slot> CreateRiscv32Slot(ArchState *state) override { + return std::make_unique<Riscv32Slot>(state); + } +}; + +// This class implements the generic DecoderInterface and provides a bridge +// to the (isa specific) generated decoder classes. +class RiscV32Decoder : public generic::DecoderInterface { + public: + using SlotEnum = SlotEnum; + using OpcodeEnum = OpcodeEnum; + + RiscV32Decoder(riscv::RiscVState *state, util::MemoryInterface *memory); + RiscV32Decoder() = delete; + ~RiscV32Decoder() override; + + // This will always return a valid instruction that can be executed. In the + // case of a decode error, the semantic function in the instruction object + // instance will raise an internal simulator error when executed. + generic::Instruction *DecodeInstruction(uint64_t address) override; + + private: + riscv::RiscVState *state_; + util::MemoryInterface *memory_; + RiscV32IsaFactory *riscv_isa_factory_; + RiscV32IEncoding *riscv_encoding_; + RiscV32IInstructionSet *riscv_isa_; + generic::DataBuffer *inst_db_; +}; + +} // namespace codelab +} // namespace sim +} // namespace mpact + +#endif // MPACT_SIM_CODELABS_RISCV_FULL_DECODER_SOLUTION_RISCV32_DECODER_H_
diff --git a/riscv_full_decoder/solution/riscv32i_encoding.cc b/riscv_full_decoder/solution/riscv32i_encoding.cc new file mode 100644 index 0000000..b0a3ca0 --- /dev/null +++ b/riscv_full_decoder/solution/riscv32i_encoding.cc
@@ -0,0 +1,171 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "riscv_full_decoder/solution/riscv32i_encoding.h" + +#include <string> + +#include "mpact/sim/generic/devnull_operand.h" +#include "mpact/sim/generic/immediate_operand.h" +#include "mpact/sim/generic/literal_operand.h" +#include "mpact/sim/generic/operand_interface.h" +#include "riscv/riscv_register.h" +#include "riscv/riscv_state.h" +#include "riscv_bin_decoder/solution/riscv32i_bin_decoder.h" + +namespace mpact { +namespace sim { +namespace codelab { + +using riscv::RiscVState; +using riscv::RV32Register; + +using generic::DevNullOperand; +using generic::ImmediateOperand; +using generic::IntLiteralOperand; + +// Generic helper functions to create register operands. +template <typename RegType> +inline DestinationOperandInterface *GetRegisterDestinationOp( + RiscVState *state, const std::string &name, int latency) { + auto [reg_ptr, unused] = state->GetRegister<RegType>(name); + return reg_ptr->CreateDestinationOperand(latency); +} + +template <typename RegType> +inline DestinationOperandInterface *GetRegisterDestinationOp( + RiscVState *state, const std::string &name, int latency, + const std::string &op_name) { + auto [reg_ptr, unused] = state->GetRegister<RegType>(name); + return reg_ptr->CreateDestinationOperand(latency, op_name); +} + +template <typename RegType> +inline SourceOperandInterface *GetRegisterSourceOp(RiscVState *state, + const std::string &name) { + auto [reg_ptr, unused] = state->GetRegister<RegType>(name); + auto *op = reg_ptr->CreateSourceOperand(); + return op; +} + +template <typename RegType> +inline SourceOperandInterface *GetRegisterSourceOp(RiscVState *state, + const std::string &name, + const std::string &op_name) { + auto [reg_ptr, unused] = state->GetRegister<RegType>(name); + auto *op = reg_ptr->CreateSourceOperand(op_name); + return op; +} + +RiscV32IEncoding::RiscV32IEncoding(RiscVState *state) : state_(state) { + InitializeSourceOperandGetters(); + InitializeDestinationOperandGetters(); +} + +// Parse the instruction word to determine the opcode. +void RiscV32IEncoding::ParseInstruction(uint32_t inst_word) { + inst_word_ = inst_word; + opcode_ = mpact::sim::codelab::DecodeRiscVInst32(inst_word_); +} + +DestinationOperandInterface *RiscV32IEncoding::GetDestination( + SlotEnum, int, OpcodeEnum, DestOpEnum dest_op, int, int latency) { + return dest_op_getters_[static_cast<int>(dest_op)](latency); +} + +SourceOperandInterface *RiscV32IEncoding::GetSource(SlotEnum, int, OpcodeEnum, + SourceOpEnum source_op, + int) { + return source_op_getters_[static_cast<int>(source_op)](); +} + +void RiscV32IEncoding::InitializeDestinationOperandGetters() { + // Destination operand getters. + dest_op_getters_[static_cast<int>(DestOpEnum::kNone)] = [](int latency) { + return nullptr; + }; + dest_op_getters_[static_cast<int>(DestOpEnum::kCsr)] = [this](int latency) { + return GetRegisterDestinationOp<RV32Register>(state_, "CSR", latency); + }; + dest_op_getters_[static_cast<int>(DestOpEnum::kNextPc)] = + [this](int latency) { + return GetRegisterDestinationOp<RV32Register>( + state_, RiscVState::kPcName, latency); + }; + dest_op_getters_[static_cast<int>(DestOpEnum::kRd)] = + [this](int latency) -> DestinationOperandInterface * { + int num = inst32_format::ExtractRd(inst_word_); + if (num == 0) return new DevNullOperand<uint32_t>(state_, {1}); + return GetRegisterDestinationOp<RV32Register>( + state_, absl::StrCat(RiscVState::kXregPrefix, num), latency, + xreg_alias_[num]); + }; +} + +void RiscV32IEncoding::InitializeSourceOperandGetters() { + // Source operand getters. + + source_op_getters_[static_cast<int>(SourceOpEnum::kNone)] = []() { + return nullptr; + }; + + // Register operands. + source_op_getters_[static_cast<int>(SourceOpEnum::kCsr)] = [this]() { + return GetRegisterSourceOp<RV32Register>(state_, "CSR"); + }; + source_op_getters_[static_cast<int>(SourceOpEnum::kRs1)] = + [this]() -> SourceOperandInterface * { + int num = inst32_format::ExtractRs1(inst_word_); + if (num == 0) return new IntLiteralOperand<0>({1}, xreg_alias_[0]); + return GetRegisterSourceOp<RV32Register>( + state_, absl::StrCat(RiscVState::kXregPrefix, num), xreg_alias_[num]); + }; + source_op_getters_[static_cast<int>(SourceOpEnum::kRs2)] = + [this]() -> SourceOperandInterface * { + int num = inst32_format::ExtractRs2(inst_word_); + if (num == 0) return new IntLiteralOperand<0>({1}, xreg_alias_[0]); + return GetRegisterSourceOp<RV32Register>( + state_, absl::StrCat(RiscVState::kXregPrefix, num), xreg_alias_[num]); + }; + + // Immediates. + source_op_getters_[static_cast<int>(SourceOpEnum::kBimm12)] = [this]() { + return new ImmediateOperand<int32_t>( + inst32_format::ExtractBImm(inst_word_)); + }; + source_op_getters_[static_cast<int>(SourceOpEnum::kImm12)] = [this]() { + return new ImmediateOperand<int32_t>( + inst32_format::ExtractImm12(inst_word_)); + }; + source_op_getters_[static_cast<int>(SourceOpEnum::kUimm5)] = [this]() { + return new ImmediateOperand<uint32_t>( + inst32_format::ExtractUimm5(inst_word_)); + }; + source_op_getters_[static_cast<int>(SourceOpEnum::kJimm20)] = [this]() { + return new ImmediateOperand<int32_t>( + inst32_format::ExtractJImm(inst_word_)); + }; + source_op_getters_[static_cast<int>(SourceOpEnum::kSimm12)] = [this]() { + return new ImmediateOperand<int32_t>( + inst32_format::ExtractSImm(inst_word_)); + }; + source_op_getters_[static_cast<int>(SourceOpEnum::kUimm20)] = [this]() { + return new ImmediateOperand<int32_t>( + inst32_format::ExtractUimm32(inst_word_)); + }; +} + +} // namespace codelab +} // namespace sim +} // namespace mpact
diff --git a/riscv_full_decoder/solution/riscv32i_encoding.h b/riscv_full_decoder/solution/riscv32i_encoding.h new file mode 100644 index 0000000..6aaa07c --- /dev/null +++ b/riscv_full_decoder/solution/riscv32i_encoding.h
@@ -0,0 +1,115 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MPACT_SIM_CODELABS_RISCV_FULL_DECODER_SOLUTION_RISCV32I_ENCODING_H_ +#define MPACT_SIM_CODELABS_RISCV_FULL_DECODER_SOLUTION_RISCV32I_ENCODING_H_ + +#include <functional> +#include <string> + +#include "absl/functional/any_invocable.h" +#include "mpact/sim/generic/operand_interface.h" +#include "riscv/riscv_state.h" +#include "riscv_isa_decoder/solution/riscv32i_decoder.h" +#include "riscv_isa_decoder/solution/riscv32i_enums.h" + +namespace mpact { +namespace sim { +namespace codelab { + +using ::mpact::sim::generic::DestinationOperandInterface; +using ::mpact::sim::generic::PredicateOperandInterface; +using ::mpact::sim::generic::SourceOperandInterface; + +// This class provides the interface between the generated instruction decoder +// framework (which is agnostic of the actual bit representation of +// instructions) and the instruction representation. This class provides methods +// to return the opcode, source operands, and destination operands for +// instructions according to the operand fields in the encoding. +class RiscV32IEncoding : public RiscV32IEncodingBase { + public: + explicit RiscV32IEncoding(riscv::RiscVState *state); + ~RiscV32IEncoding() override = default; + + // Parses an instruction and determines the opcode. + void ParseInstruction(uint32_t inst_word); + + // RiscV32 has a single slot type and single entry, so the following methods + // ignore the SlotEnum parameter. + + // Returns the opcode in the current instruction representation. + OpcodeEnum GetOpcode(SlotEnum, int) override { return opcode_; } + + // There is no predicate, so return nullptr. + PredicateOperandInterface *GetPredicate(SlotEnum, int, OpcodeEnum, + PredOpEnum) override { + return nullptr; + } + // The following method returns a source operand that corresponds to the + // particular operand field. + SourceOperandInterface *GetSource(SlotEnum, int, OpcodeEnum, SourceOpEnum op, + int) override; + + // The following method returns a destination operand that corresponds to the + // particular operand field. + DestinationOperandInterface *GetDestination(SlotEnum, int, OpcodeEnum, + DestOpEnum op, int, + int latency) override; + // This method returns latency for any destination operand for which the + // latency specifier in the .isa file is '*'. Since there are none, just + // return 0. + int GetLatency(SlotEnum, int, OpcodeEnum, DestOpEnum, int) override { + return 0; + } + + ResourceOperandInterface *GetSimpleResourceOperand(SlotEnum, int, OpcodeEnum, + SimpleResourceVector &, + int) override { + return nullptr; + } + + ResourceOperandInterface *GetComplexResourceOperand(SlotEnum, int, OpcodeEnum, + ComplexResourceEnum, int, + int) override { + return nullptr; + } + + private: + // These two methods initialize the source and destination operand getter + // arrays. + void InitializeSourceOperandGetters(); + void InitializeDestinationOperandGetters(); + + riscv::RiscVState *state_; + uint32_t inst_word_; + OpcodeEnum opcode_; + + absl::AnyInvocable<SourceOperandInterface *()> + source_op_getters_[static_cast<int>(SourceOpEnum::kPastMaxValue)]; + absl::AnyInvocable<DestinationOperandInterface *(int)> + dest_op_getters_[static_cast<int>(DestOpEnum::kPastMaxValue)]; + + const std::string xreg_alias_[32] = { + "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", "s0", "s1", "a0", + "a1", "a2", "a3", "a4", "a5", "a6", "a7", "s2", "s3", "s4", "s5", + "s6", "s7", "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6"}; +}; + +} // namespace codelab +} // namespace sim +} // namespace mpact + +#endif // MPACT_SIM_CODELABS_RISCV_FULL_DECODER_SOLUTION_RISCV32I_ENCODING_H_
diff --git a/riscv_isa_decoder/BUILD b/riscv_isa_decoder/BUILD new file mode 100644 index 0000000..8963230 --- /dev/null +++ b/riscv_isa_decoder/BUILD
@@ -0,0 +1,32 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Build file for the isa_decoder part of the RiscV instruction decoder codelab. + +load("@mpact-sim//mpact/sim/decoder:mpact_sim_isa.bzl", "mpact_isa_decoder") + +package( + default_applicable_licenses = ["//:license"], + default_visibility = ["//visibility:public"], +) + +mpact_isa_decoder( + name = "riscv32i_isa", + src = "riscv32i.isa", + includes = [], + isa_name = "RiscV32I", + deps = [ + "//riscv_semantic_functions:riscv32i", + ], +)
diff --git a/riscv_isa_decoder/riscv32i.isa b/riscv_isa_decoder/riscv32i.isa new file mode 100644 index 0000000..56f809f --- /dev/null +++ b/riscv_isa_decoder/riscv32i.isa
@@ -0,0 +1,81 @@ +// This file is used for the go/mpact-sim-codelabs/instruction-decoder +// codelab. It will contain instruction decode information for a subset +// of the RiscV32I architecture. + +isa RiscV32I { + namespace mpact::sim::codelab; + slots { riscv32; } +} + +// The RiscV 'I' instructions. +slot riscv32i { + // Include file that contains the declarations of the semantic functions for + // the 'I' instructions. + includes { + #include "riscv_semantic_functions/rv32i_instructions.h" + } + // These are all 32 bit instructions, so set default size to 4. + default size = 4; + // Model these with 0 latency to avoid buffering the result. Since RiscV + // instructions have sequential semantics this is fine. + default latency = 0; + // The opcodes. + opcodes { + + // Add the instruction definition for the instructions in the codelab + // at the place holders below. + // + // Note Exercise 1 does not involve adding instructions. + + // Exercise 2, Add Register-Register ALU Instructions. + + // Exercise 3, Add ALU Instructions with Immediates. + + // Exercise 4, Add Branch and Jump-And-Link Instructions. + + // Exercise 5, Add Store Instructions. + + // Exercise 6, Add Load Instructions. + + // End of Excercises. + fence{: imm12 : }, + semfunc: "&RV32IFence", + disasm: "fence"; + ebreak{}, + semfunc: "&RV32IEbreak", + disasm: "ebreak"; + } +} + +// RiscV32 CSR manipulation instructions. +slot zicsr { + // Include file that contains the declarations of the semantic functions for + // the 'zicsr' instructions. + includes { + #include "riscv_semantic_functions/zicsr_instructions.h" + } + // 32 bit instructions. + default size = 4; + // No buffering of the result. + default latency = 0; + // Instructions. + opcodes { + csrs{: rs1, csr : rd, csr}, + semfunc: "&RV32ZiCsrs", + disasm: "csrs", "%csr, %rs1"; + csrw_nr{: rs1 : csr}, + semfunc: "&RV32ZiCsrwNr", // rd == 0 (x0). + disasm: "csrw", "%csr, %rs1"; + csrs_nw{: csr : rd, csr}, + semfunc: "&RV32ZiCsrsNw", // rs1 == 0 (x0). + disasm: "csrs", "%csr, %rd"; + } +} + +// The final instruction set combines riscv32i and zicsr. +slot riscv32 : riscv32i, zicsr { + // Default opcode for any instruction not matched by the decoder. + default opcode = + disasm: "Illegal instruction at 0x%(@:08x)", + semfunc: "&RV32IllegalInstruction"; +}
diff --git a/riscv_isa_decoder/solution/BUILD b/riscv_isa_decoder/solution/BUILD new file mode 100644 index 0000000..c82dfd9 --- /dev/null +++ b/riscv_isa_decoder/solution/BUILD
@@ -0,0 +1,32 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Build file for the isa_decoder part of the RiscV instruction decoder codelab solution. + +load("@mpact-sim//mpact/sim/decoder:mpact_sim_isa.bzl", "mpact_isa_decoder") + +package( + default_applicable_licenses = ["//:license"], + default_visibility = ["//visibility:public"], +) + +mpact_isa_decoder( + name = "riscv32i_isa", + src = "riscv32i.isa", + includes = [], + isa_name = "RiscV32I", + deps = [ + "//riscv_semantic_functions/solution:riscv32i", + ], +)
diff --git a/riscv_isa_decoder/solution/riscv32i.isa b/riscv_isa_decoder/solution/riscv32i.isa new file mode 100644 index 0000000..5ce4c9e --- /dev/null +++ b/riscv_isa_decoder/solution/riscv32i.isa
@@ -0,0 +1,178 @@ +// This file contains the ISA description for the RiscV32G architecture. + +isa RiscV32I { + namespace mpact::sim::codelab; + slots { riscv32; } +} + +// The RiscV 'I' instructions. +slot riscv32i { + // Include file that contains the declarations of the semantic functions for + // the 'I' instructions. + includes { + #include "riscv_semantic_functions/solution/rv32i_instructions.h" + } + // These are all 32 bit instructions, so set default size to 4. + default size = 4; + // Model these with 0 latency to avoid buffering the result. Since RiscV + // instructions have sequential semantics this is fine. + default latency = 0; + // The opcodes. + opcodes { + // Exercise 2, Add Register-Register ALU Instructions. + add{ : rs1, rs2 : rd}, + semfunc: "&RV32IAdd", + disasm: "add", "%rd, %rs1, %rs2"; + and{ : rs1, rs2 : rd}, + semfunc: "&RV32IAnd", + disasm: "and", "%rd, %rs1, %rs2"; + or{ : rs1, rs2 : rd}, + semfunc: "&RV32IOr", + disasm: "or", "%rd, %rs1, %rs2"; + sll{ : rs1, rs2 : rd}, + semfunc: "&RV32ISll", + disasm: "sll", "%rd, %rs1, %rs2"; + sltu{ : rs1, rs2 : rd}, + semfunc: "&RV32ISltu", + disasm: "sltu", "%rd, %rs1, %rs2"; + sub{ : rs1, rs2 : rd}, + semfunc: "&RV32ISub", + disasm: "sub", "%rd, %rs1, %rs2"; + xor{ : rs1, rs2 : rd}, + semfunc: "&RV32IXor", + disasm: "xor", "%rd, %rs1, %rs2"; + + // Exercise 3, Add ALU Instructions with Immediates. + // I-Type. + addi{ : rs1, imm12 : rd}, + semfunc: "&RV32IAdd", + disasm: "addi", "%rd, %rs1, %imm12"; + andi{ : rs1, imm12 : rd}, + semfunc: "&RV32IAnd", + disasm: "andi", "%rd, %rs1, %imm12"; + ori{ : rs1, imm12 : rd}, + semfunc: "&RV32IOr", + disasm: "ori", "%rd, %rs1, %imm12"; + xori{ : rs1, imm12 : rd}, + semfunc: "&RV32IXor", + disasm: "xori", "%rd, %rs1, %imm12"; + + // Specialized I-Type. + slli{ : rs1, uimm5 : rd}, + semfunc: "&RV32ISll", + disasm: "slli", "%rd, %rs1, %uimm5"; + srai{ : rs1, uimm5 : rd}, + semfunc: "&RV32ISra", + disasm: "srai", "%rd, %rs1, %uimm5"; + srli{ : rs1, uimm5 : rd}, + semfunc: "&RV32ISrl", + disasm: "srli", "%rd, %rs1, %uimm5"; + + // U-Type. + auipc{ : uimm20 : rd}, + semfunc: "&RV32IAuipc", + disasm: "auipc", "%rd, %uimm20"; + lui{ : uimm20 : rd}, + semfunc: "&RV32ILui", + disasm: "lui", "%rd, %uimm20"; + + // Exercise 4, Add Branch and Jump-And-Link Instructions. + // Branches + beq{ : rs1, rs2, bimm12 : next_pc}, + semfunc: "&RV32IBeq", + disasm: "beq", "%rs1, %rs2, %(@+bimm12:08x)"; + bge{ : rs1, rs2, bimm12 : next_pc}, + semfunc: "&RV32IBge", + disasm: "bge", "%rs1, %rs2, %(@+bimm12:08x)"; + bgeu{ : rs1, rs2, bimm12 : next_pc}, + semfunc: "&RV32IBgeu", + disasm: "bgeu", "%rs1, %rs2, %(@+bimm12:08x)"; + blt{ : rs1, rs2, bimm12 : next_pc}, + semfunc: "&RV32IBlt", + disasm: "blt", "%rs1, %rs2, %(@+bimm12:08x)"; + bltu{ : rs1, rs2, bimm12 : next_pc}, + semfunc: "&RV32IBltu", + disasm: "bltu", "%rs1, %rs2, %(@+bimm12:08x)"; + bne{ : rs1, rs2, bimm12 : next_pc}, + semfunc: "&RV32IBne", + disasm: "bne", "%rs1, %rs2, %(@+bimm12:08x)"; + + // Jumps + jal{ : jimm20 : next_pc, rd}, + semfunc: "&RV32IJal", + disasm: "jal", "%rd, %(@+jimm20:08x)"; + jalr{ : rs1, imm12 : next_pc, rd}, + semfunc: "&RV32IJalr", + disasm: "jalr", "%rd, %rs1, %imm12"; + + // Exercise 5, Add Store Instructions. + sb{ : rs1, simm12, rs2}, + semfunc: "&RV32ISb", + disasm: "sb", "%rs2, %simm12(%rs1)"; + sh{ : rs1, simm12, rs2}, + semfunc: "&RV32ISh", + disasm: "sh", "%rs2, %simm12(%rs1)"; + sw{ : rs1, simm12, rs2}, + semfunc: "&RV32ISw", + disasm: "sw", "%rs2, %simm12(%rs1)"; + + // Exercise 6, Add Load Instructions. + lb{( : rs1, imm12 : ), ( : : rd)}, + semfunc: "&RV32ILb", "&RV32ILbChild", + disasm: "lb", "%rd, %imm12(%rs1)"; + lbu{( : rs1, imm12 : ), ( : : rd)}, + semfunc: "&RV32ILbu", "&RV32ILbuChild", + disasm: "lbu", "%rd, %imm12(%rs1)"; + lh{( : rs1, imm12 : ), ( : : rd)}, + semfunc: "&RV32ILh", "&RV32ILhChild", + disasm: "lh", "%rd, %imm12(%rs1)"; + lhu{( : rs1, imm12 : ), ( : : rd)}, + semfunc: "&RV32ILhu", "&RV32ILhuChild", + disasm: "lhu", "%rd, %imm12(%rs1)"; + lw{( : rs1, imm12 : ), ( : : rd)}, + semfunc: "&RV32ILw", "&RV32ILwChild", + disasm: "lw", "%rd, %imm12(%rs1)"; + + // End of Excercises. + + fence{: imm12 : }, + semfunc: "&RV32IFence", + disasm: "fence"; + ebreak{}, + semfunc: "&RV32IEbreak", + disasm: "ebreak"; + } +} + +// RiscV32 CSR manipulation instructions. +slot zicsr { + // Include file that contains the declarations of the semantic functions for + // the 'zicsr' instructions. + includes { + #include "riscv_semantic_functions/solution/zicsr_instructions.h" + } + // 32 bit instructions. + default size = 4; + // No buffering of the result. + default latency = 0; + // Instructions. + opcodes { + csrs{: rs1, csr : rd, csr}, + semfunc: "&RV32ZiCsrs", + disasm: "csrs", "%csr, %rs1"; + csrw_nr{: rs1 : csr}, + semfunc: "&RV32ZiCsrwNr", // rd == 0 (x0). + disasm: "csrw", "%csr, %rs1"; + csrs_nw{: csr : rd, csr}, + semfunc: "&RV32ZiCsrsNw", // rs1 == 0 (x0). + disasm: "csrs", "%csr, %rd"; + } +} + +// The final instruction set combines riscv32i and zicsr. +slot riscv32 : riscv32i, zicsr { + // Default opcode for any instruction not matched by the decoder. + default opcode = + disasm: "Illegal instruction at 0x%(@:08x)", + semfunc: "&RV32IllegalInstruction"; +}
diff --git a/riscv_semantic_functions/BUILD b/riscv_semantic_functions/BUILD new file mode 100644 index 0000000..97c914a --- /dev/null +++ b/riscv_semantic_functions/BUILD
@@ -0,0 +1,40 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Semantic functions for the MPACT-Sim codelab + +package( + default_applicable_licenses = ["//:license"], + default_visibility = ["//visibility:public"], +) + +cc_library( + name = "riscv32i", + srcs = [ + "rv32i_instructions.cc", + "zicsr_instructions.cc", + ], + hdrs = [ + "rv32i_instructions.h", + "zicsr_instructions.h", + ], + copts = ["-O3"], + deps = [ + "@mpact-riscv//riscv:riscv_state", + "@mpact-sim//mpact/sim/generic:arch_state", + "@mpact-sim//mpact/sim/generic:core", + "@mpact-sim//mpact/sim/generic:instruction", + "@mpact-sim//mpact/sim/util/memory", + ], +)
diff --git a/riscv_semantic_functions/rv32i_instructions.cc b/riscv_semantic_functions/rv32i_instructions.cc new file mode 100644 index 0000000..18a746f --- /dev/null +++ b/riscv_semantic_functions/rv32i_instructions.cc
@@ -0,0 +1,147 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "riscv_semantic_functions/rv32i_instructions.h" + +#include <functional> +#include <iostream> + +#include "mpact/sim/generic/arch_state.h" +#include "mpact/sim/generic/data_buffer.h" +#include "mpact/sim/generic/instruction_helpers.h" +#include "riscv/riscv_state.h" + +namespace mpact { +namespace sim { +namespace codelab { + +using generic::DataBuffer; +using riscv::RiscVState; + +void RV32IllegalInstruction(Instruction *inst) { + inst->state() + ->program_error_controller() + ->GetProgramError(generic::ProgramErrorController::kInternalErrorName) + ->Raise( + absl::StrCat("Illegal instruction at ", absl::Hex(inst->address()))); + std::cerr << absl::StrCat("Illegal instruction at 0x", + absl::Hex(inst->address()), "\n"); +} + +// The following instruction semantic functions implement basic alu operations. +// They are used for both register-register and register-immediate versions of +// the corresponding instructions. + +// Semantic functions for Exercise 2. +void RV32IAdd(Instruction *instruction) {} + +void RV32IAnd(Instruction *instruction) {} + +void RV32IOr(Instruction *instruction) {} + +void RV32ISll(Instruction *instruction) {} + +void RV32ISltu(Instruction *instruction) {} + +void RV32ISra(Instruction *instruction) {} + +void RV32ISrl(Instruction *instruction) {} + +void RV32ISub(Instruction *instruction) {} + +void RV32IXor(Instruction *instruction) {} +// End semantic functions for exercise 2. + +// Semantic functions for Exercise 3. +// Load upper immediate. It is assumed that the decoder already shifted the +// immediate. +void RV32ILui(Instruction *instruction) {} + +// Add upper immediate to PC (for PC relative addressing). It is assumed that +// the decoder already shifted the immediate. +void RV32IAuipc(Instruction *instruction) {} +// End semantic functions for Exercise 3. + +// Semantic functions for Exercise 4. +// Branch instructions. +void RV32IBeq(Instruction *instruction) {} + +void RV32IBge(Instruction *instruction) {} + +void RV32IBgeu(Instruction *instruction) {} + +void RV32IBlt(Instruction *instruction) {} + +void RV32IBltu(Instruction *instruction) {} + +void RV32IBne(Instruction *instruction) {} + +// Jal instruction. +void RV32IJal(Instruction *instruction) {} + +// Jalr instruction. +void RV32IJalr(Instruction *instruction) {} +// End of semantic functions for Exercise 4. + +// Semantic functions for Exercise 5. +// Store instructions. +void RV32ISw(Instruction *instruction) {} + +void RV32ISh(Instruction *instruction) {} + +void RV32ISb(Instruction *instruction) {} +// End of semantic functions for Exercise 5. + +// Semantic functions for Exercise 6. +// Load instructions. +void RV32ILw(Instruction *instruction) {} + +void RV32ILwChild(Instruction *instruction) {} + +void RV32ILh(Instruction *instruction) {} + +void RV32ILhChild(Instruction *instruction) {} + +void RV32ILhu(Instruction *instruction) {} + +void RV32ILhuChild(Instruction *instruction) {} + +void RV32ILb(Instruction *instruction) {} + +void RV32ILbChild(Instruction *instruction) {} + +void RV32ILbu(Instruction *instruction) {} + +void RV32ILbuChild(Instruction *instruction) {} +// End of semantic functions for Exercise 6. + +// Fence. +void RV32IFence(Instruction *instruction) { + uint32_t bits = instruction->Source(0)->AsUint32(0); + int fm = (bits >> 8) & 0xf; + int predecessor = (bits >> 4) & 0xf; + int successor = bits & 0xf; + auto *state = static_cast<RiscVState *>(instruction->state()); + state->Fence(instruction, fm, predecessor, successor); +} + +// Ebreak - software breakpoint instruction. +void RV32IEbreak(Instruction *instruction) { + auto *state = static_cast<RiscVState *>(instruction->state()); + state->EBreak(instruction); +} + +} // namespace codelab +} // namespace sim +} // namespace mpact
diff --git a/riscv_semantic_functions/rv32i_instructions.h b/riscv_semantic_functions/rv32i_instructions.h new file mode 100644 index 0000000..002e085 --- /dev/null +++ b/riscv_semantic_functions/rv32i_instructions.h
@@ -0,0 +1,106 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MPACT_SIM_CODELABS_SEMANTIC_FUNCTIONS_RV32I_INSTRUCTIONS_H_ +#define MPACT_SIM_CODELABS_SEMANTIC_FUNCTIONS_RV32I_INSTRUCTIONS_H_ + +#include "mpact/sim/generic/instruction.h" + +// This file contains the declarations of the instruction semantic functions +// for the RiscV 32i instructions. + +namespace mpact { +namespace sim { +namespace codelab { + +using ::mpact::sim::generic::Instruction; + +// +// All semantic functions must have the signature void(Instruction *). +// + +// For the following, source operand 0 refers to the register specified in rs1, +// and source operand 1 refers to either the register specified in rs2, or the +// immediate. Destination operand 0 refers to the register specified in rd. + +// Semantic functions for Exercise 2. +// End semantic functions for Exercise 2. + +// For the following, source operand 0 refers to the 20-bit immediate value, +// already shifted left by 12 to form a 32-bit immediate. + +// Semantic functions for Exercise 3. +// End semantic functions for Exercise 3. + +// For the following branch instructions. Source operand 0 refers to the +// register specified by rs1, source operand 2 refers to the register specified +// by rs2, and source operand 3 refers to the immediate offset. Destination +// operand 0 refers to the pc destination operand. + +// Semantic functions for Exercise 4 - branches. +// End semantic functions for Exercise 4 - branches. + +// Source operand 0 contains the immediate value. Destination operand 0 refers +// to the pc destination operand, wheras destination operand 1 refers to the +// link register specified in rd. + +// Semantic function for Exercise 4 - jal. +// End semantic function for Exercise 4 - jal. + +// Source operand 0 refers to the base registers specified by rs1, source +// operand 1 contains the immediate value. Destination operand 0 refers to the +// pc destination operand, wheras destination operand 1 refers to the +// link register specified in rd. + +// Semantic function for Exercise 4 - jalr. +// End semantic functions for Exercise 4 - jalr. + +// For each store instruction semantic function, source operand 0 is the base +// register, source operand 1 is the offset, while source operand 2 is the value +// to be stored referred to by rs2. + +// Semantic functions for Exercise 5. +// End semantic functions for Exercise 5. + +// Each of the load instructions are modeled by a pair of semantic instruction +// functions. The "main" function computes the effective address and initiates +// the load, the "child" function processes the load result and writes it back +// to the destination register. +// For the "main" semantic function, source operand 0 is the base register, +// source operand 1 the offset. Destination operand 0 is the register specified +// by rd. The "child" semantic function will get a copy of the destination +// operand. + +// Semantic functions for Exercise 6. +// End semantic functions for Exercise 6. + +// Exercises End. + +// The Fence instruction takes a single source operand (index 0) which consists +// of an immediate value containing the right justified concatenation of the FM, +// predecessor, and successor bit fields of the instruction. +void RV32IFence(Instruction *instruction); + +// Software breakpoint instruction. +void RV32IEbreak(Instruction *instruction); + +void RV32IllegalInstruction(Instruction *inst); + +} // namespace codelab +} // namespace sim +} // namespace mpact + +#endif // MPACT_SIM_CODELABS_SEMANTIC_FUNCTIONS_RV32I_INSTRUCTIONS_H_
diff --git a/riscv_semantic_functions/solution/BUILD b/riscv_semantic_functions/solution/BUILD new file mode 100644 index 0000000..97c914a --- /dev/null +++ b/riscv_semantic_functions/solution/BUILD
@@ -0,0 +1,40 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Semantic functions for the MPACT-Sim codelab + +package( + default_applicable_licenses = ["//:license"], + default_visibility = ["//visibility:public"], +) + +cc_library( + name = "riscv32i", + srcs = [ + "rv32i_instructions.cc", + "zicsr_instructions.cc", + ], + hdrs = [ + "rv32i_instructions.h", + "zicsr_instructions.h", + ], + copts = ["-O3"], + deps = [ + "@mpact-riscv//riscv:riscv_state", + "@mpact-sim//mpact/sim/generic:arch_state", + "@mpact-sim//mpact/sim/generic:core", + "@mpact-sim//mpact/sim/generic:instruction", + "@mpact-sim//mpact/sim/util/memory", + ], +)
diff --git a/riscv_semantic_functions/solution/rv32i_instructions.cc b/riscv_semantic_functions/solution/rv32i_instructions.cc new file mode 100644 index 0000000..3be4551 --- /dev/null +++ b/riscv_semantic_functions/solution/rv32i_instructions.cc
@@ -0,0 +1,283 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "riscv_semantic_functions/solution/rv32i_instructions.h" + +#include <cstdint> +#include <functional> +#include <iostream> + +#include "mpact/sim/generic/arch_state.h" +#include "mpact/sim/generic/data_buffer.h" +#include "mpact/sim/generic/instruction_helpers.h" +#include "riscv/riscv_state.h" + +namespace mpact { +namespace sim { +namespace codelab { + +using generic::DataBuffer; +using riscv::RiscVState; + +void RV32IllegalInstruction(Instruction *inst) { + inst->state() + ->program_error_controller() + ->GetProgramError(generic::ProgramErrorController::kInternalErrorName) + ->Raise( + absl::StrCat("Illegal instruction at ", absl::Hex(inst->address()))); + std::cerr << absl::StrCat("Illegal instruction at 0x", + absl::Hex(inst->address()), "\n"); +} + +// The following instruction semantic functions implement basic alu operations. +// They are used for both register-register and register-immediate versions of +// the corresponding instructions. + +// Semantic functions for Exercise 2. +void RV32IAdd(Instruction *instruction) { + generic::BinaryOp<uint32_t>(instruction, + [](uint32_t a, uint32_t b) { return a + b; }); +} + +void RV32IAnd(Instruction *instruction) { + generic::BinaryOp<uint32_t>(instruction, + [](uint32_t a, uint32_t b) { return a & b; }); +} + +void RV32IOr(Instruction *instruction) { + generic::BinaryOp<uint32_t>(instruction, + [](uint32_t a, uint32_t b) { return a | b; }); +} + +void RV32ISll(Instruction *instruction) { + generic::BinaryOp<uint32_t>( + instruction, [](uint32_t a, uint32_t b) { return a << (b & 0x1f); }); +} + +void RV32ISltu(Instruction *instruction) { + generic::BinaryOp<uint32_t>( + instruction, [](uint32_t a, uint32_t b) { return (a < b) ? 1 : 0; }); +} + +void RV32ISra(Instruction *instruction) { + generic::BinaryOp<uint32_t, int32_t, uint32_t>( + instruction, [](int32_t a, uint32_t b) { return a >> (b & 0x1f); }); +} + +void RV32ISrl(Instruction *instruction) { + generic::BinaryOp<uint32_t>( + instruction, [](uint32_t a, uint32_t b) { return a >> (b & 0x1f); }); +} + +void RV32ISub(Instruction *instruction) { + generic::BinaryOp<uint32_t>(instruction, + [](uint32_t a, uint32_t b) { return a - b; }); +} + +void RV32IXor(Instruction *instruction) { + generic::BinaryOp<uint32_t>(instruction, + [](uint32_t a, uint32_t b) { return a ^ b; }); +} +// End semantic functions for exercise 2. + +// Semantic functions for Exercise 3. +// Load upper immediate. It is assumed that the decoder already shifted the +// immediate. +void RV32ILui(Instruction *instruction) { + generic::UnaryOp<uint32_t>(instruction, [](uint32_t a) { return a; }); +} + +// Add upper immediate to PC (for PC relative addressing). It is assumed that +// the decoder already shifted the immediate. +void RV32IAuipc(Instruction *instruction) { + generic::UnaryOp<uint32_t>(instruction, [instruction](uint32_t a) { + return a + instruction->address(); + }); +} +// End semantic functions for Exercise 3. + +// Semantic functions for Exercise 4. +// Branch instructions. + +template <typename OperandType> +static inline void BranchConditional( + Instruction *instruction, + std::function<bool(OperandType, OperandType)> cond) { + OperandType a = generic::GetInstructionSource<OperandType>(instruction, 0); + OperandType b = generic::GetInstructionSource<OperandType>(instruction, 1); + if (cond(a, b)) { + uint32_t offset = generic::GetInstructionSource<uint32_t>(instruction, 2); + uint32_t target = offset + instruction->address(); + DataBuffer *db = instruction->Destination(0)->AllocateDataBuffer(); + db->Set<uint32_t>(0, target); + db->Submit(); + } +} + +void RV32IBeq(Instruction *instruction) { + BranchConditional<uint32_t>(instruction, + [](uint32_t a, uint32_t b) { return a == b; }); +} + +void RV32IBge(Instruction *instruction) { + BranchConditional<int32_t>(instruction, + [](int32_t a, int32_t b) { return a >= b; }); +} + +void RV32IBgeu(Instruction *instruction) { + BranchConditional<uint32_t>(instruction, + [](uint32_t a, uint32_t b) { return a >= b; }); +} + +void RV32IBlt(Instruction *instruction) { + BranchConditional<int32_t>(instruction, + [](int32_t a, int32_t b) { return a < b; }); +} + +void RV32IBltu(Instruction *instruction) { + BranchConditional<uint32_t>(instruction, + [](uint32_t a, uint32_t b) { return a < b; }); +} + +void RV32IBne(Instruction *instruction) { + BranchConditional<uint32_t>(instruction, + [](uint32_t a, uint32_t b) { return a != b; }); +} + +// Jal instruction. +void RV32IJal(Instruction *instruction) { + uint32_t offset = instruction->Source(0)->AsUint32(0); + uint32_t target = offset + instruction->address(); + uint32_t return_address = instruction->address() + instruction->size(); + auto *db = instruction->Destination(0)->AllocateDataBuffer(); + db->Set<uint32_t>(0, target); + db->Submit(); + db = instruction->Destination(1)->AllocateDataBuffer(); + db->Set<uint32_t>(0, return_address); + db->Submit(); +} + +// Jalr instruction. +void RV32IJalr(Instruction *instruction) { + uint32_t reg_base = instruction->Source(0)->AsUint32(0); + uint32_t offset = instruction->Source(1)->AsUint32(0); + uint32_t target = offset + reg_base; + uint32_t return_address = instruction->address() + instruction->size(); + auto *db = instruction->Destination(0)->AllocateDataBuffer(); + db->Set<uint32_t>(0, target); + db->Submit(); + db = instruction->Destination(1)->AllocateDataBuffer(); + db->Set<uint32_t>(0, return_address); + db->Submit(); +} +// End of semantic functions for Exercise 4. + +// Semantic functions for Exercise 5. +// Store instructions. + +template <typename ValueType> +inline void StoreValue(Instruction *instruction) { + auto base = generic::GetInstructionSource<uint32_t>(instruction, 0); + auto offset = generic::GetInstructionSource<uint32_t>(instruction, 1); + uint32_t address = base + offset; + auto value = generic::GetInstructionSource<ValueType>(instruction, 2); + auto *state = static_cast<RiscVState *>(instruction->state()); + auto *db = state->db_factory()->Allocate(sizeof(ValueType)); + db->Set<ValueType>(0, value); + state->StoreMemory(instruction, address, db); + db->DecRef(); +} + +void RV32ISw(Instruction *instruction) { StoreValue<uint32_t>(instruction); } + +void RV32ISh(Instruction *instruction) { StoreValue<uint16_t>(instruction); } + +void RV32ISb(Instruction *instruction) { StoreValue<uint8_t>(instruction); } + +// End of semantic functions for Exercise 5. + +// Semantic functions for Exercise 6. +// Load instructions. +template <typename ValueType> +inline void LoadValue(Instruction *instruction) { + auto base = generic::GetInstructionSource<uint32_t>(instruction, 0); + auto offset = generic::GetInstructionSource<uint32_t>(instruction, 1); + uint32_t address = base + offset; + auto *state = static_cast<RiscVState *>(instruction->state()); + auto *db = state->db_factory()->Allocate(sizeof(ValueType)); + db->set_latency(0); + auto *context = new riscv::LoadContext(db); + state->LoadMemory(instruction, address, db, instruction->child(), context); + context->DecRef(); +} + +template <typename ValueType> +inline void LoadValueChild(Instruction *instruction) { + auto *context = static_cast<riscv::LoadContext *>(instruction->context()); + uint32_t value = static_cast<uint32_t>(context->value_db->Get<ValueType>(0)); + auto *db = instruction->Destination(0)->AllocateDataBuffer(); + db->Set<uint32_t>(0, value); + db->Submit(); +} + +void RV32ILw(Instruction *instruction) { LoadValue<uint32_t>(instruction); } + +void RV32ILwChild(Instruction *instruction) { + LoadValueChild<uint32_t>(instruction); +} + +void RV32ILh(Instruction *instruction) { LoadValue<int16_t>(instruction); } + +void RV32ILhChild(Instruction *instruction) { + LoadValueChild<int16_t>(instruction); +} + +void RV32ILhu(Instruction *instruction) { LoadValue<uint16_t>(instruction); } + +void RV32ILhuChild(Instruction *instruction) { + LoadValueChild<uint16_t>(instruction); +} + +void RV32ILb(Instruction *instruction) { LoadValue<int8_t>(instruction); } + +void RV32ILbChild(Instruction *instruction) { + LoadValueChild<int8_t>(instruction); +} + +void RV32ILbu(Instruction *instruction) { LoadValue<uint8_t>(instruction); } + +void RV32ILbuChild(Instruction *instruction) { + LoadValueChild<uint8_t>(instruction); +} +// End of semantic functions for Exercise 6. + +// Fence. +void RV32IFence(Instruction *instruction) { + uint32_t bits = instruction->Source(0)->AsUint32(0); + int fm = (bits >> 8) & 0xf; + int predecessor = (bits >> 4) & 0xf; + int successor = bits & 0xf; + auto *state = static_cast<RiscVState *>(instruction->state()); + state->Fence(instruction, fm, predecessor, successor); +} + +// Ebreak - software breakpoint instruction. +void RV32IEbreak(Instruction *instruction) { + auto *state = static_cast<RiscVState *>(instruction->state()); + state->EBreak(instruction); +} + +} // namespace codelab +} // namespace sim +} // namespace mpact
diff --git a/riscv_semantic_functions/solution/rv32i_instructions.h b/riscv_semantic_functions/solution/rv32i_instructions.h new file mode 100644 index 0000000..c236cf9 --- /dev/null +++ b/riscv_semantic_functions/solution/rv32i_instructions.h
@@ -0,0 +1,138 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MPACT_SIM_CODELABS_SEMANTIC_FUNCTIONS_SOLUTION_RV32I_INSTRUCTIONS_H_ +#define MPACT_SIM_CODELABS_SEMANTIC_FUNCTIONS_SOLUTION_RV32I_INSTRUCTIONS_H_ + +#include "mpact/sim/generic/instruction.h" + +// This file contains the declarations of the instruction semantic functions +// for the RiscV 32i instructions. + +namespace mpact { +namespace sim { +namespace codelab { + +using ::mpact::sim::generic::Instruction; + +// +// All semantic functions must have the signature void(Instruction *). +// + +// For the following, source operand 0 refers to the register specified in rs1, +// and source operand 1 refers to either the register specified in rs2, or the +// immediate. Destination operand 0 refers to the register specified in rd. + +// Semantic functions for Exercise 2. +void RV32IAdd(Instruction *instruction); +void RV32IAnd(Instruction *instruction); +void RV32IOr(Instruction *instruction); +void RV32ISll(Instruction *instruction); +void RV32ISltu(Instruction *instruction); +void RV32ISub(Instruction *instruction); +void RV32ISra(Instruction *instruction); +void RV32ISrl(Instruction *instruction); +void RV32IXor(Instruction *instruction); +// End semantic functions for Exercise 2. + +// For the following, source operand 0 refers to the 20-bit immediate value, +// already shifted left by 12 to form a 32-bit immediate. + +// Semantic functions for Exercise 3. +void RV32ILui(Instruction *instruction); +void RV32IAuipc(Instruction *instruction); +// End semantic functions for Exercise 3. + +// For the following branch instructions. Source operand 0 refers to the +// register specified by rs1, source operand 2 refers to the register specified +// by rs2, and source operand 3 refers to the immediate offset. Destination +// operand 0 refers to the pc destination operand. + +// Semantic functions for Exercise 4 - branches. +void RV32IBeq(Instruction *instruction); +void RV32IBge(Instruction *instruction); +void RV32IBgeu(Instruction *instruction); +void RV32IBlt(Instruction *instruction); +void RV32IBltu(Instruction *instruction); +void RV32IBne(Instruction *instruction); +// End semantic functions for Exercise 4 - branches. + +// Source operand 0 contains the immediate value. Destination operand 0 refers +// to the pc destination operand, wheras destination operand 1 refers to the +// link register specified in rd. + +// Semantic function for Exercise 4 - jal. +void RV32IJal(Instruction *instruction); +// End semantic function for Exercise 4 - jal. + +// Source operand 0 refers to the base registers specified by rs1, source +// operand 1 contains the immediate value. Destination operand 0 refers to the +// pc destination operand, wheras destination operand 1 refers to the +// link register specified in rd. + +// Semantic function for Exercise 4 - jalr. +void RV32IJalr(Instruction *instruction); +// End semantic functions for Exercise 4 - jalr. + +// For each store instruction semantic function, source operand 0 is the base +// register, source operand 1 is the offset, while source operand 2 is the value +// to be stored referred to by rs2. + +// Semantic functions for Exercise 5. +void RV32ISb(Instruction *instruction); +void RV32ISh(Instruction *instruction); +void RV32ISw(Instruction *instruction); +// End semantic functions for Exercise 5. + +// Each of the load instructions are modeled by a pair of semantic instruction +// functions. The "main" function computes the effective address and initiates +// the load, the "child" function processes the load result and writes it back +// to the destination register. +// For the "main" semantic function, source operand 0 is the base register, +// source operand 1 the offset. Destination operand 0 is the register specified +// by rd. The "child" semantic function will get a copy of the destination +// operand. + +// Semantic functions for Exercise 6. +void RV32ILb(Instruction *instruction); +void RV32ILbChild(Instruction *instruction); +void RV32ILbu(Instruction *instruction); +void RV32ILbuChild(Instruction *instruction); +void RV32ILh(Instruction *instruction); +void RV32ILhChild(Instruction *instruction); +void RV32ILhu(Instruction *instruction); +void RV32ILhuChild(Instruction *instruction); +void RV32ILw(Instruction *instruction); +void RV32ILwChild(Instruction *instruction); +// End semantic functions for Exercise 6. + +// Exercises End. + +// The Fence instruction takes a single source operand (index 0) which consists +// of an immediate value containing the right justified concatenation of the FM, +// predecessor, and successor bit fields of the instruction. +void RV32IFence(Instruction *instruction); + +// Software breakpoint instruction. +void RV32IEbreak(Instruction *instruction); + +void RV32IllegalInstruction(Instruction *inst); + +} // namespace codelab +} // namespace sim +} // namespace mpact + +#endif // MPACT_SIM_CODELABS_SEMANTIC_FUNCTIONS_SOLUTION_RV32I_INSTRUCTIONS_H_
diff --git a/riscv_semantic_functions/solution/zicsr_instructions.cc b/riscv_semantic_functions/solution/zicsr_instructions.cc new file mode 100644 index 0000000..02a60a8 --- /dev/null +++ b/riscv_semantic_functions/solution/zicsr_instructions.cc
@@ -0,0 +1,35 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "riscv_semantic_functions/solution/zicsr_instructions.h" + +namespace mpact { +namespace sim { +namespace codelab { + +void RV32ZiCsrs(Instruction *instruction) { + // TODO(): Fill in semantics. +} + +void RV32ZiCsrwNr(Instruction *instruction) { + // TODO(): Fill in semantics. +} + +void RV32ZiCsrsNw(Instruction *instruction) { + // TODO(): Fill in semantics. +} + +} // namespace codelab +} // namespace sim +} // namespace mpact
diff --git a/riscv_semantic_functions/solution/zicsr_instructions.h b/riscv_semantic_functions/solution/zicsr_instructions.h new file mode 100644 index 0000000..3f140a5 --- /dev/null +++ b/riscv_semantic_functions/solution/zicsr_instructions.h
@@ -0,0 +1,36 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MPACT_SIM_CODELABS_SEMANTIC_FUNCTIONS_SOLUTION_ZICSR_INSTRUCTIONS_H_ +#define MPACT_SIM_CODELABS_SEMANTIC_FUNCTIONS_SOLUTION_ZICSR_INSTRUCTIONS_H_ + +#include "mpact/sim/generic/instruction.h" + +namespace mpact { +namespace sim { +namespace codelab { + +using ::mpact::sim::generic::Instruction; + +void RV32ZiCsrs(Instruction *instruction); +void RV32ZiCsrwNr(Instruction *instruction); +void RV32ZiCsrsNw(Instruction *instruction); + +} // namespace codelab +} // namespace sim +} // namespace mpact + +#endif // MPACT_SIM_CODELABS_SEMANTIC_FUNCTIONS_SOLUTION_ZICSR_INSTRUCTIONS_H_
diff --git a/riscv_semantic_functions/zicsr_instructions.cc b/riscv_semantic_functions/zicsr_instructions.cc new file mode 100644 index 0000000..e13b9ff --- /dev/null +++ b/riscv_semantic_functions/zicsr_instructions.cc
@@ -0,0 +1,35 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "riscv_semantic_functions/zicsr_instructions.h" + +namespace mpact { +namespace sim { +namespace codelab { + +void RV32ZiCsrs(Instruction *instruction) { + // TODO(): Fill in semantics. +} + +void RV32ZiCsrwNr(Instruction *instruction) { + // TODO(): Fill in semantics. +} + +void RV32ZiCsrsNw(Instruction *instruction) { + // TODO(): Fill in semantics. +} + +} // namespace codelab +} // namespace sim +} // namespace mpact
diff --git a/riscv_semantic_functions/zicsr_instructions.h b/riscv_semantic_functions/zicsr_instructions.h new file mode 100644 index 0000000..788b572 --- /dev/null +++ b/riscv_semantic_functions/zicsr_instructions.h
@@ -0,0 +1,36 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MPACT_SIM_CODELABS_SEMANTIC_FUNCTIONS_ZICSR_INSTRUCTIONS_H_ +#define MPACT_SIM_CODELABS_SEMANTIC_FUNCTIONS_ZICSR_INSTRUCTIONS_H_ + +#include "mpact/sim/generic/instruction.h" + +namespace mpact { +namespace sim { +namespace codelab { + +using ::mpact::sim::generic::Instruction; + +void RV32ZiCsrs(Instruction *instruction); +void RV32ZiCsrwNr(Instruction *instruction); +void RV32ZiCsrsNw(Instruction *instruction); + +} // namespace codelab +} // namespace sim +} // namespace mpact + +#endif // MPACT_SIM_CODELABS_SEMANTIC_FUNCTIONS_ZICSR_INSTRUCTIONS_H_