aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoss Kettleson <kettro@google.com>2023-03-21 14:59:09 -0700
committerRoss Kettleson <kettro@google.com>2023-03-21 14:59:09 -0700
commit033862392a6f028b15898ddcb70da99f488a9797 (patch)
treed59bb754e9438dc70bd618f32c2f0f86d35e2358
parent3a28018c8903c27c0e817829429e7efc75fa1102 (diff)
downloadtock-registers-033862392a6f028b15898ddcb70da99f488a9797.tar.gz
Initial import of tock-registers crate
Change-Id: If72cfd606808e53714098afea9b122b4f39007eb Signed-off-by: Ross Kettleson <kettro@google.com>
-rw-r--r--Android.bp22
-rw-r--r--CHANGELOG.md100
-rw-r--r--Cargo.toml41
-rw-r--r--Cargo.toml.orig23
-rw-r--r--LICENSE202
-rw-r--r--METADATA19
-rw-r--r--MODULE_LICENSE_APACHE20
-rw-r--r--NOTICE202
-rw-r--r--OWNERS1
-rw-r--r--README.md468
-rw-r--r--src/fields.rs771
-rw-r--r--src/interfaces.rs309
-rw-r--r--src/lib.rs128
-rw-r--r--src/local_register.rs129
-rw-r--r--src/macros.rs370
-rw-r--r--src/registers.rs181
16 files changed, 2966 insertions, 0 deletions
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..65cb665
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,22 @@
+// This file is generated by cargo2android.py --tests --device --run.
+// Do not modify this file as changes will be overridden on upgrade.
+
+
+
+rust_library {
+ name: "libtock_registers",
+ host_supported: true,
+ crate_name: "tock_registers",
+ cargo_env_compat: true,
+ cargo_pkg_version: "0.8.1",
+ srcs: ["src/lib.rs"],
+ edition: "2021",
+ features: [
+ "default",
+ "register_types",
+ ],
+ apex_available: [
+ "//apex_available:platform",
+ "//apex_available:anyapex",
+ ],
+}
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..fbf1f6b
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,100 @@
+# Changelog
+
+## master
+
+## v0.8.1
+
+A point release to allow multiple invocations of `register_fields!` in
+the same module. See the PR and linked Issue for details.
+
+ - #3230: don't encapsulate test_fields! tests in mod
+
+## v0.8
+
+`tock-registers` now supports stable Rust!
+
+There is a small breaking change, documented below, required to support
+Rust 2021 edition. Most of the remaining changes are improvements to the
+internal self-testing infrastructure and documentation. There are also
+some additions to `FieldValue` to improve ergonomics.
+
+### **Breaking Changes**
+
+ - #2842: tock-registers: rename TryFromValue::try_from to try_from_value
+ - #2838: Update to Rust 2021 edition
+
+### Other Changes
+
+ - #3126: [trivial] tock-registers: mark two methods as `const`
+ - #3088: tock_registers/test_fields: respect struct size padding w/ alignment
+ - #3072: Update Rust nightly version + Expose virtual-function-elimination
+ - libraries/tock-register-interface: Fixup register_structs documentation
+ - #2988: Remove const_fn_trait_bound feature and update nightly (Mar 2022)
+ - #3014: tock-registers: Implement From field enum value type for FieldValue
+ - #3013: tock-register-interface: Provide none method for FieldValue type
+ - #2916: tock-register-interface: improve read_as_enum documentation
+ - #2922: tock-register-interface: replace register tests by const assertions
+
+## v0.7
+
+ - #2642: Rename `IntLike` to `UIntLike` to match semantics
+ - #2618: Reorganize, document, and feature-gate modules and exports
+ - #2589: Upgrade nightly for `const_fn` -> `const_fn_trait_bound`
+ - #2517: Use traits for accessing / manipulating registers
+ - #2512: Fix `Copy` and `Clone` implementation on `Field`
+ - #2300: Add support for `usize`
+ - #2220: Remove duplicate code, make local register copy read-write
+ - #2210: Add `u128` to `IntLike`
+ - #2197: Accept trailing comma in bitfields and bitmasks
+
+## v0.6
+
+ - #2095: Fix syntax errors and inconsistencies in documentation
+ - #2071: Clarify bit widths in documentation examples
+ - #2015: Use UnsafeCell in registers (see issue #2005)
+ - #1939: Make the Field::mask and FieldValue::mask fields private
+ - #1823: Allow large unsigned values as bitmasks + add bitmask! helper macro
+ - #1554: Allow lifetime parameters for `register_structs! { Foo<'a> { ..`
+ - #1661: Add `Aliased` register type for MMIO with differing R/W behavior
+
+## v0.5
+
+ - #1510
+ - Register visibility granularity: don't automatically make everything
+ `pub`, rather give creation macro callers visbility control.
+
+ - #1489
+ - Make `register_structs!` unit test generation opt-out, so that
+ `custom-test-frameworks` environments can disable them.
+
+ - #1481
+ - Add `#[derive(Copy, Clone)]` to InMemoryRegister.
+
+ - #1428
+ - Implement `mask()` for `FieldValue<u16>` which seems to have been
+ skipped at some point.
+ - Implement `read()` for `FieldValue` so that individual fields
+ can be extracted from a register `FieldValue` representation.
+
+ - #1461: Update `register_structs` macro to support flexible visibility of each
+ struct and each field. Also revert to private structs by default.
+
+## v0.4.1
+
+ - #1458: Update struct macro to create `pub` structs
+
+## v0.4
+
+ - #1368: Remove `new()` and add `InMemoryRegister`
+ - #1410: Add new macro for generating structs
+
+## v0.3
+
+ - #1243: Update to Rust 2018 (nightly)
+ - #1250: Doc-only: Fix some rustdoc warnings
+
+## v0.2
+
+ - #1161: Add `read_as_enum` to `LocalRegisterCopy`; thanks @andre-richter
+
+## v0.1 - Initial Release
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..00d5c8d
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,41 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2021"
+name = "tock-registers"
+version = "0.8.1"
+authors = ["Tock Project Developers <tock-dev@googlegroups.com>"]
+description = "Memory-Mapped I/O and register interface developed for Tock."
+homepage = "https://www.tockos.org/"
+readme = "README.md"
+keywords = [
+ "tock",
+ "embedded",
+ "registers",
+ "mmio",
+ "bare-metal",
+]
+categories = [
+ "data-structures",
+ "embedded",
+ "no-std",
+]
+license = "MIT/Apache-2.0"
+repository = "https://github.com/tock/tock/tree/master/libraries/tock-register-interface"
+
+[features]
+default = ["register_types"]
+register_types = []
+
+[badges.travis-ci]
+branch = "master"
+repository = "tock/tock"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
new file mode 100644
index 0000000..052ddd8
--- /dev/null
+++ b/Cargo.toml.orig
@@ -0,0 +1,23 @@
+[package]
+name = "tock-registers"
+version = "0.8.1"
+authors = ["Tock Project Developers <tock-dev@googlegroups.com>"]
+description = "Memory-Mapped I/O and register interface developed for Tock."
+homepage = "https://www.tockos.org/"
+repository = "https://github.com/tock/tock/tree/master/libraries/tock-register-interface"
+readme = "README.md"
+keywords = ["tock", "embedded", "registers", "mmio", "bare-metal"]
+categories = ["data-structures", "embedded", "no-std"]
+license = "MIT/Apache-2.0"
+edition = "2021"
+
+[badges]
+travis-ci = { repository = "tock/tock", branch = "master" }
+
+[features]
+default = [ "register_types" ]
+
+# Include actual register types (except LocalRegisterCopy). Disabling
+# the feature makes this an interface-only library and removes all
+# usage of unsafe code
+register_types = []
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/METADATA b/METADATA
new file mode 100644
index 0000000..3107a6b
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,19 @@
+name: "tock-registers"
+description: "Memory-Mapped I/O and register interface developed for Tock."
+third_party {
+ url {
+ type: HOMEPAGE
+ value: "https://crates.io/crates/tock-registers"
+ }
+ url {
+ type: ARCHIVE
+ value: "https://static.crates.io/crates/tock-registers/tock-registers-0.8.1.crate"
+ }
+ version: "0.8.1"
+ license_type: NOTICE
+ last_upgrade_date {
+ year: 2023
+ month: 3
+ day: 13
+ }
+}
diff --git a/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_APACHE2
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/NOTICE
@@ -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/OWNERS b/OWNERS
new file mode 100644
index 0000000..45dc4dd
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1 @@
+include platform/prebuilts/rust:master:/OWNERS
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..de9067b
--- /dev/null
+++ b/README.md
@@ -0,0 +1,468 @@
+# Tock Register Interface
+
+This crate provides an interface and types for defining and
+manipulating registers and bitfields.
+
+## Defining registers
+
+The crate provides three types for working with memory mapped registers:
+`ReadWrite`, `ReadOnly`, and `WriteOnly`, providing read-write, read-only, and
+write-only functionality, respectively. These types implement the `Readable`,
+`Writeable` and `ReadWriteable` traits.
+
+Defining the registers is done with the `register_structs` macro, which expects
+for each register an offset, a field name, and a type. Registers must be
+declared in increasing order of offsets and contiguously. Gaps when defining the
+registers must be explicitly annotated with an offset and gap identifier (by
+convention using a field named `_reservedN`), but without a type. The macro will
+then automatically take care of calculating the gap size and inserting a
+suitable filler struct. The end of the struct is marked with its size and the
+`@END` keyword, effectively pointing to the offset immediately past the list of
+registers.
+
+```rust
+use tock_registers::registers::{ReadOnly, ReadWrite, WriteOnly};
+
+register_structs! {
+ Registers {
+ // Control register: read-write
+ // The 'Control' parameter constrains this register to only use fields from
+ // a certain group (defined below in the bitfields section).
+ (0x000 => cr: ReadWrite<u8, Control::Register>),
+
+ // Status register: read-only
+ (0x001 => s: ReadOnly<u8, Status::Register>),
+
+ // Registers can be bytes, halfwords, or words:
+ // Note that the second type parameter can be omitted, meaning that there
+ // are no bitfields defined for these registers.
+ (0x002 => byte0: ReadWrite<u8>),
+ (0x003 => byte1: ReadWrite<u8>),
+ (0x004 => short: ReadWrite<u16>),
+
+ // Empty space between registers must be marked with a padding field,
+ // declared as follows. The length of this padding is automatically
+ // computed by the macro.
+ (0x006 => _reserved),
+ (0x008 => word: ReadWrite<u32>),
+
+ // The type for a register can be anything. Conveniently, you can use an
+ // array when there are a bunch of similar registers.
+ (0x00C => array: [ReadWrite<u32>; 4]),
+ (0x01C => ... ),
+
+ // Etc.
+
+ // The end of the struct is marked as follows.
+ (0x100 => @END),
+ }
+}
+```
+
+This generates a C-style struct of the following form.
+
+```rust
+#[repr(C)]
+struct Registers {
+ // Control register: read-write
+ // The 'Control' parameter constrains this register to only use fields from
+ // a certain group (defined below in the bitfields section).
+ cr: ReadWrite<u8, Control::Register>,
+
+ // Status register: read-only
+ s: ReadOnly<u8, Status::Register>
+
+ // Registers can be bytes, halfwords, or words:
+ // Note that the second type parameter can be omitted, meaning that there
+ // are no bitfields defined for these registers.
+ byte0: ReadWrite<u8>,
+ byte1: ReadWrite<u8>,
+ short: ReadWrite<u16>,
+
+ // The padding length was automatically computed as 0x008 - 0x006.
+ _reserved: [u8; 2],
+ word: ReadWrite<u32>,
+
+ // Arrays are expanded as-is, like any other type.
+ array: [ReadWrite<u32>; 4],
+
+ // Etc.
+}
+```
+
+This crate will generate additional, compile time (`const`) assertions
+to validate various invariants of the register structs, such as
+
+- proper start offset of padding fields,
+- proper start and end offsets of actual fields,
+- invalid alignment of field types,
+- the `@END` marker matching the size of the struct.
+
+For more information on the generated assertions, check out the [`test_fields!`
+macro documentation](https://docs.tockos.org/tock_registers/macro.test_fields.html).
+
+By default, the visibility of the generated structs and fields is private. You
+can make them public using the `pub` keyword, just before the struct name or the
+field identifier.
+
+For example, the following call to the macro:
+
+```rust
+register_structs! {
+ pub Registers {
+ (0x000 => foo: ReadOnly<u32>),
+ (0x004 => pub bar: ReadOnly<u32>),
+ (0x008 => @END),
+ }
+}
+```
+
+will generate the following struct.
+
+```rust
+#[repr(C)]
+pub struct Registers {
+ foo: ReadOnly<u32>,
+ pub bar: ReadOnly<u32>,
+}
+```
+
+## Defining bitfields
+
+Bitfields are defined through the `register_bitfields!` macro:
+
+```rust
+register_bitfields! [
+ // First parameter is the register width. Can be u8, u16, u32, or u64.
+ u32,
+
+ // Each subsequent parameter is a register abbreviation, its descriptive
+ // name, and its associated bitfields.
+ // The descriptive name defines this 'group' of bitfields. Only registers
+ // defined as ReadWrite<_, Control::Register> can use these bitfields.
+ Control [
+ // Bitfields are defined as:
+ // name OFFSET(shift) NUMBITS(num) [ /* optional values */ ]
+
+ // This is a two-bit field which includes bits 4 and 5
+ RANGE OFFSET(4) NUMBITS(2) [
+ // Each of these defines a name for a value that the bitfield can be
+ // written with or matched against. Note that this set is not exclusive--
+ // the field can still be written with arbitrary constants.
+ VeryHigh = 0,
+ High = 1,
+ Low = 2
+ ],
+
+ // A common case is single-bit bitfields, which usually just mean
+ // 'enable' or 'disable' something.
+ EN OFFSET(3) NUMBITS(1) [],
+ INT OFFSET(2) NUMBITS(1) []
+ ],
+
+ // Another example:
+ // Status register
+ Status [
+ TXCOMPLETE OFFSET(0) NUMBITS(1) [],
+ TXINTERRUPT OFFSET(1) NUMBITS(1) [],
+ RXCOMPLETE OFFSET(2) NUMBITS(1) [],
+ RXINTERRUPT OFFSET(3) NUMBITS(1) [],
+ MODE OFFSET(4) NUMBITS(3) [
+ FullDuplex = 0,
+ HalfDuplex = 1,
+ Loopback = 2,
+ Disabled = 3
+ ],
+ ERRORCOUNT OFFSET(6) NUMBITS(3) []
+ ],
+
+ // In a simple case, offset can just be a number, and the number of bits
+ // is set to 1:
+ InterruptFlags [
+ UNDES 10,
+ TXEMPTY 9,
+ NSSR 8,
+ OVRES 3,
+ MODF 2,
+ TDRE 1,
+ RDRF 0
+ ]
+]
+```
+
+## Register Interface Summary
+
+There are four types provided by the register interface: `ReadOnly`,
+`WriteOnly`, `ReadWrite`, and `Aliased`. They expose the following
+methods, through the implementations of the `Readable`, `Writeable`
+and `ReadWriteable` traits respectively:
+
+```rust
+ReadOnly<T: UIntLike, R: RegisterLongName = ()>: Readable
+.get() -> T // Get the raw register value
+.read(field: Field<T, R>) -> T // Read the value of the given field
+.read_as_enum<E>(field: Field<T, R>) -> Option<E> // Read value of the given field as a enum member
+.is_set(field: Field<T, R>) -> bool // Check if one or more bits in a field are set
+.matches_any(value: FieldValue<T, R>) -> bool // Check if any specified parts of a field match
+.matches_all(value: FieldValue<T, R>) -> bool // Check if all specified parts of a field match
+.extract() -> LocalRegisterCopy<T, R> // Make local copy of register
+
+WriteOnly<T: UIntLike, R: RegisterLongName = ()>: Writeable
+.set(value: T) // Set the raw register value
+.write(value: FieldValue<T, R>) // Write the value of one or more fields,
+ // overwriting other fields to zero
+ReadWrite<T: UIntLike, R: RegisterLongName = ()>: Readable + Writeable + ReadWriteable
+.get() -> T // Get the raw register value
+.set(value: T) // Set the raw register value
+.read(field: Field<T, R>) -> T // Read the value of the given field
+.read_as_enum<E>(field: Field<T, R>) -> Option<E> // Read value of the given field as a enum member
+.write(value: FieldValue<T, R>) // Write the value of one or more fields,
+ // overwriting other fields to zero
+.modify(value: FieldValue<T, R>) // Write the value of one or more fields,
+ // leaving other fields unchanged
+.modify_no_read( // Write the value of one or more fields,
+ original: LocalRegisterCopy<T, R>, // leaving other fields unchanged, but pass in
+ value: FieldValue<T, R>) // the original value, instead of doing a register read
+.is_set(field: Field<T, R>) -> bool // Check if one or more bits in a field are set
+.matches_any(value: FieldValue<T, R>) -> bool // Check if any specified parts of a field match
+.matches_all(value: FieldValue<T, R>) -> bool // Check if all specified parts of a field match
+.extract() -> LocalRegisterCopy<T, R> // Make local copy of register
+
+Aliased<T: UIntLike, R: RegisterLongName = (), W: RegisterLongName = ()>: Readable + Writeable
+.get() -> T // Get the raw register value
+.set(value: T) // Set the raw register value
+.read(field: Field<T, R>) -> T // Read the value of the given field
+.read_as_enum<E>(field: Field<T, R>) -> Option<E> // Read value of the given field as a enum member
+.write(value: FieldValue<T, W>) // Write the value of one or more fields,
+ // overwriting other fields to zero
+.is_set(field: Field<T, R>) -> bool // Check if one or more bits in a field are set
+.matches_any(value: FieldValue<T, R>) -> bool // Check if any specified parts of a field match
+.matches_all(value: FieldValue<T, R>) -> bool // Check if all specified parts of a field match
+.extract() -> LocalRegisterCopy<T, R> // Make local copy of register
+```
+
+The `Aliased` type represents cases where read-only and write-only registers,
+with different meanings, are aliased to the same memory location.
+
+The first type parameter (the `UIntLike` type) is `u8`, `u16`, `u32`,
+`u64`, `u128` or `usize`.
+
+## Example: Using registers and bitfields
+
+Assuming we have defined a `Registers` struct and the corresponding bitfields as
+in the previous two sections. We also have an immutable reference to the
+`Registers` struct, named `registers`.
+
+```rust
+// -----------------------------------------------------------------------------
+// RAW ACCESS
+// -----------------------------------------------------------------------------
+
+// Get or set the raw value of the register directly. Nothing fancy:
+registers.cr.set(registers.cr.get() + 1);
+
+
+// -----------------------------------------------------------------------------
+// READ
+// -----------------------------------------------------------------------------
+
+// `range` will contain the value of the RANGE field, e.g. 0, 1, 2, or 3.
+// The type annotation is not necessary, but provided for clarity here.
+let range: u8 = registers.cr.read(Control::RANGE);
+
+// Or one can read `range` as a enum and `match` over it.
+let range = registers.cr.read_as_enum(Control::RANGE);
+match range {
+ Some(Control::RANGE::Value::VeryHigh) => { /* ... */ }
+ Some(Control::RANGE::Value::High) => { /* ... */ }
+ Some(Control::RANGE::Value::Low) => { /* ... */ }
+
+ None => unreachable!("invalid value")
+}
+
+// `en` will be 0 or 1
+let en: u8 = registers.cr.read(Control::EN);
+
+
+// -----------------------------------------------------------------------------
+// MODIFY
+// -----------------------------------------------------------------------------
+
+// Write a value to a bitfield without altering the values in other fields:
+registers.cr.modify(Control::RANGE.val(2)); // Leaves EN, INT unchanged
+
+// Named constants can be used instead of the raw values:
+registers.cr.modify(Control::RANGE::VeryHigh);
+
+// Enum values can also be used:
+registers.cr.modify(Control::RANGE::Value::VeryHigh.into())
+
+// Another example of writing a field with a raw value:
+registers.cr.modify(Control::EN.val(0)); // Leaves RANGE, INT unchanged
+
+// For one-bit fields, the named values SET and CLEAR are automatically
+// defined:
+registers.cr.modify(Control::EN::SET);
+
+// Write multiple values at once, without altering other fields:
+registers.cr.modify(Control::EN::CLEAR + Control::RANGE::Low); // INT unchanged
+
+// Any number of non-overlapping fields can be combined:
+registers.cr.modify(Control::EN::CLEAR + Control::RANGE::High + CR::INT::SET);
+
+// In some cases (such as a protected register) .modify() may not be appropriate.
+// To enable updating a register without coupling the read and write, use
+// modify_no_read():
+let original = registers.cr.extract();
+registers.cr.modify_no_read(original, Control::EN::CLEAR);
+
+
+// -----------------------------------------------------------------------------
+// WRITE
+// -----------------------------------------------------------------------------
+
+// Same interface as modify, except that all unspecified fields are overwritten to zero.
+registers.cr.write(Control::RANGE.val(1)); // implictly sets all other bits to zero
+
+// -----------------------------------------------------------------------------
+// BITFLAGS
+// -----------------------------------------------------------------------------
+
+// For one-bit fields, easily check if they are set or clear:
+let txcomplete: bool = registers.s.is_set(Status::TXCOMPLETE);
+
+// -----------------------------------------------------------------------------
+// MATCHING
+// -----------------------------------------------------------------------------
+
+// You can also query a specific register state easily with `matches_[any|all]`:
+
+// Doesn't care about the state of any field except TXCOMPLETE and MODE:
+let ready: bool = registers.s.matches_all(Status::TXCOMPLETE:SET +
+ Status::MODE::FullDuplex);
+
+// This is very useful for awaiting for a specific condition:
+while !registers.s.matches_all(Status::TXCOMPLETE::SET +
+ Status::RXCOMPLETE::SET +
+ Status::TXINTERRUPT::CLEAR) {}
+
+// Or for checking whether any interrupts are enabled:
+let any_ints = registers.s.matches_any(Status::TXINTERRUPT + Status::RXINTERRUPT);
+
+// Also you can read a register with set of enumerated values as a enum and `match` over it:
+let mode = registers.cr.read_as_enum(Status::MODE);
+
+match mode {
+ Some(Status::MODE::Value::FullDuplex) => { /* ... */ }
+ Some(Status::MODE::Value::HalfDuplex) => { /* ... */ }
+
+ None => unreachable!("invalid value")
+}
+
+// -----------------------------------------------------------------------------
+// LOCAL COPY
+// -----------------------------------------------------------------------------
+
+// More complex code may want to read a register value once and then keep it in
+// a local variable before using the normal register interface functions on the
+// local copy.
+
+// Create a copy of the register value as a local variable.
+let local = registers.cr.extract();
+
+// Now all the functions for a ReadOnly register work.
+let txcomplete: bool = local.is_set(Status::TXCOMPLETE);
+
+// -----------------------------------------------------------------------------
+// In-Memory Registers
+// -----------------------------------------------------------------------------
+
+// In some cases, code may want to edit a memory location with all of the
+// register features described above, but the actual memory location is not a
+// fixed MMIO register but instead an arbitrary location in memory. If this
+// location is then shared with the hardware (i.e. via DMA) then the code
+// must do volatile reads and writes since the value may change without the
+// software knowing. To support this, the library includes an `InMemoryRegister`
+// type.
+
+let control: InMemoryRegister<u32, Control::Register> = InMemoryRegister::new(0)
+control.write(Contol::BYTE_COUNT.val(0) +
+ Contol::ENABLE::Yes +
+ Contol::LENGTH.val(10));
+```
+
+Note that `modify` performs exactly one volatile load and one volatile store,
+`write` performs exactly one volatile store, and `read` performs exactly one
+volatile load. Thus, you are ensured that a single call will set or query all
+fields simultaneously.
+
+## Performance
+
+Examining the binaries while testing this interface, everything compiles
+down to the optimal inlined bit twiddling instructions--in other words, there is
+zero runtime cost, as far as an informal preliminary study has found.
+
+## Nice type checking
+
+This interface helps the compiler catch some common types of bugs via type checking.
+
+If you define the bitfields for e.g. a control register, you can give them a
+descriptive group name like `Control`. This group of bitfields will only work
+with a register of the type `ReadWrite<_, Control>` (or `ReadOnly/WriteOnly`,
+etc). For instance, if we have the bitfields and registers as defined above,
+
+```rust
+// This line compiles, because registers.cr is associated with the Control group
+// of bitfields.
+registers.cr.modify(Control::RANGE.val(1));
+
+// This line will not compile, because registers.s is associated with the Status
+// group, not the Control group.
+let range = registers.s.read(Control::RANGE);
+```
+
+## Naming conventions
+
+There are several related names in the register definitions. Below is a
+description of the naming convention for each:
+
+```rust
+use tock_registers::registers::ReadWrite;
+
+#[repr(C)]
+struct Registers {
+ // The register name in the struct should be a lowercase version of the
+ // register abbreviation, as written in the datasheet:
+ cr: ReadWrite<u8, Control::Register>,
+}
+
+register_bitfields! [
+ u8,
+
+ // The name should be the long descriptive register name,
+ // camelcase, without the word 'register'.
+ Control [
+ // The field name should be the capitalized abbreviated
+ // field name, as given in the datasheet.
+ RANGE OFFSET(4) NUMBITS(3) [
+ // Each of the field values should be camelcase,
+ // as descriptive of their value as possible.
+ VeryHigh = 0,
+ High = 1,
+ Low = 2
+ ]
+ ]
+]
+```
+
+## Implementing custom register types
+
+The `Readable`, `Writeable` and `ReadWriteable` traits make it
+possible to implement custom register types, even outside of this
+crate. A particularly useful application area for this are CPU
+registers, such as ARM SPSRs or RISC-V CSRs. It is sufficient to
+implement the `Readable::get` and `Writeable::set` methods for the
+rest of the API to be automatically implemented by the crate-provided
+traits. For more in-depth documentation on how this works, [refer to
+the `interfaces` module
+documentation](https://docs.tockos.org/tock_registers/index.html).
diff --git a/src/fields.rs b/src/fields.rs
new file mode 100644
index 0000000..e0bf661
--- /dev/null
+++ b/src/fields.rs
@@ -0,0 +1,771 @@
+//! Register bitfield types and macros
+//!
+//! To conveniently access and manipulate fields of a register, this
+//! library provides types and macros to describe and access bitfields
+//! of a register. This can be especially useful in conjuction with
+//! the APIs defined in [`interfaces`](crate::interfaces), which make
+//! use of these types and hence allow to access and manipulate
+//! bitfields of proper registers directly.
+//!
+//! A specific section (bitfield) in a register is described by the
+//! [`Field`] type, consisting of an unshifted bitmask over the base
+//! register [`UIntLike`](crate::UIntLike) type, and a shift
+//! parameter. It is further associated with a specific
+//! [`RegisterLongName`], which can prevent its use with incompatible
+//! registers.
+//!
+//! A value of a section of a register is described by the
+//! [`FieldValue`] type. It stores the information of the respective
+//! section in the register, as well as the associated value. A
+//! [`FieldValue`] can be created from a [`Field`] through the
+//! [`val`](Field::val) method.
+//!
+//! ## `register_bitfields` macro
+//!
+//! For defining register layouts with an associated
+//! [`RegisterLongName`](crate::RegisterLongName), along with
+//! [`Field`]s and matching [`FieldValue`]s, a convenient macro-based
+//! interface can be used.
+//!
+//! The following example demonstrates how two registers can be
+//! defined, over a `u32` base type:
+//!
+//! ```rust
+//! # use tock_registers::register_bitfields;
+//! # use tock_registers::registers::InMemoryRegister;
+//! # use tock_registers::interfaces::{Readable, ReadWriteable};
+//! register_bitfields![u32,
+//! Uart [
+//! ENABLE OFFSET(0) NUMBITS(4) [
+//! ON = 8,
+//! OFF = 0
+//! ]
+//! ],
+//! Psel [
+//! PIN OFFSET(0) NUMBITS(6),
+//! CONNECT OFFSET(31) NUMBITS(1)
+//! ],
+//! ];
+//!
+//! // In this scope, `Uart` is a module, representing the register and
+//! // its fields. `Uart::Register` is a `RegisterLongName` type
+//! // identifying this register. `Uart::ENABLE` is a field covering the
+//! // first 4 bits of this register. `Uart::ENABLE::ON` is a
+//! // `FieldValue` over that field, with the associated value 8.
+//! // We can now use the types like so:
+//! let reg: InMemoryRegister<u32, Uart::Register> = InMemoryRegister::new(0);
+//! assert!(reg.read(Uart::ENABLE) == 0x00000000);
+//! reg.modify(Uart::ENABLE::ON);
+//! assert!(reg.get() == 0x00000008);
+//! ```
+
+// The register interface uses `+` in a way that is fine for bitfields, but
+// looks unusual (and perhaps problematic) to a linter. We just ignore those
+// lints for this file.
+#![allow(clippy::suspicious_op_assign_impl)]
+#![allow(clippy::suspicious_arithmetic_impl)]
+
+use core::marker::PhantomData;
+use core::ops::{Add, AddAssign};
+
+use crate::{RegisterLongName, UIntLike};
+
+/// Specific section of a register.
+///
+/// For the Field, the mask is unshifted, ie. the LSB should always be set.
+pub struct Field<T: UIntLike, R: RegisterLongName> {
+ pub mask: T,
+ pub shift: usize,
+ associated_register: PhantomData<R>,
+}
+
+impl<T: UIntLike, R: RegisterLongName> Field<T, R> {
+ pub const fn new(mask: T, shift: usize) -> Field<T, R> {
+ Field {
+ mask: mask,
+ shift: shift,
+ associated_register: PhantomData,
+ }
+ }
+
+ #[inline]
+ pub fn read(self, val: T) -> T {
+ (val & (self.mask << self.shift)) >> self.shift
+ }
+
+ #[inline]
+ /// Check if one or more bits in a field are set
+ pub fn is_set(self, val: T) -> bool {
+ val & (self.mask << self.shift) != T::zero()
+ }
+
+ #[inline]
+ /// Read value of the field as an enum member
+ ///
+ /// This method expects to be passed the unasked and unshifted register
+ /// value, extracts the field value by calling [`Field::read`] and
+ /// subsequently passes that value to the [`TryFromValue`] implementation on
+ /// the passed enum type.
+ ///
+ /// The [`register_bitfields!`](crate::register_bitfields) macro will
+ /// generate an enum containing the various named field variants and
+ /// implementing the required [`TryFromValue`] trait. It is accessible as
+ /// `$REGISTER_NAME::$FIELD_NAME::Value`.
+ ///
+ /// This method can be useful to symbolically represent read register field
+ /// states throughout the codebase and to enforce exhaustive matches over
+ /// all defined valid register field values.
+ ///
+ /// ## Usage Example
+ ///
+ /// ```rust
+ /// # use tock_registers::interfaces::Readable;
+ /// # use tock_registers::registers::InMemoryRegister;
+ /// # use tock_registers::register_bitfields;
+ /// register_bitfields![u8,
+ /// EXAMPLEREG [
+ /// TESTFIELD OFFSET(3) NUMBITS(3) [
+ /// Foo = 2,
+ /// Bar = 3,
+ /// Baz = 6,
+ /// ],
+ /// ],
+ /// ];
+ ///
+ /// match EXAMPLEREG::TESTFIELD.read_as_enum(0x9C) {
+ /// Some(EXAMPLEREG::TESTFIELD::Value::Bar) => "The value is 3!",
+ /// _ => panic!("boo!"),
+ /// };
+ /// ```
+ pub fn read_as_enum<E: TryFromValue<T, EnumType = E>>(self, val: T) -> Option<E> {
+ E::try_from_value(self.read(val))
+ }
+}
+
+// #[derive(Copy, Clone)] won't work here because it will use
+// incorrect bounds, as a result of using a PhantomData over the
+// generic R. The PhantomData<R> implements Copy regardless of whether
+// R does, but the #[derive(Copy, Clone)] generates
+//
+// #[automatically_derived]
+// #[allow(unused_qualifications)]
+// impl<T: ::core::marker::Copy + UIntLike,
+// R: ::core::marker::Copy + RegisterLongName>
+// ::core::marker::Copy for Field<T, R> {}
+//
+// , so Field will only implement Copy if R: Copy.
+//
+// Manually implementing Clone and Copy works around this issue.
+//
+// Relevant Rust issue: https://github.com/rust-lang/rust/issues/26925
+impl<T: UIntLike, R: RegisterLongName> Clone for Field<T, R> {
+ fn clone(&self) -> Self {
+ Field {
+ mask: self.mask,
+ shift: self.shift,
+ associated_register: self.associated_register,
+ }
+ }
+}
+impl<T: UIntLike, R: RegisterLongName> Copy for Field<T, R> {}
+
+macro_rules! Field_impl_for {
+ ($type:ty) => {
+ impl<R: RegisterLongName> Field<$type, R> {
+ pub const fn val(&self, value: $type) -> FieldValue<$type, R> {
+ FieldValue::<$type, R>::new(self.mask, self.shift, value)
+ }
+ }
+ };
+}
+
+Field_impl_for!(u8);
+Field_impl_for!(u16);
+Field_impl_for!(u32);
+Field_impl_for!(u64);
+Field_impl_for!(u128);
+Field_impl_for!(usize);
+
+/// Values for the specific register fields.
+///
+/// For the FieldValue, the masks and values are shifted into their actual
+/// location in the register.
+#[derive(Copy, Clone)]
+pub struct FieldValue<T: UIntLike, R: RegisterLongName> {
+ mask: T,
+ pub value: T,
+ associated_register: PhantomData<R>,
+}
+
+macro_rules! FieldValue_impl_for {
+ ($type:ty) => {
+ // Necessary to split the implementation of new() out because the bitwise
+ // math isn't treated as const when the type is generic.
+ // Tracking issue: https://github.com/rust-lang/rfcs/pull/2632
+ impl<R: RegisterLongName> FieldValue<$type, R> {
+ pub const fn new(mask: $type, shift: usize, value: $type) -> Self {
+ FieldValue {
+ mask: mask << shift,
+ value: (value & mask) << shift,
+ associated_register: PhantomData,
+ }
+ }
+ }
+
+ // Necessary to split the implementation of From<> out because of the orphan rule
+ // for foreign trait implementation (see [E0210](https://doc.rust-lang.org/error-index.html#E0210)).
+ impl<R: RegisterLongName> From<FieldValue<$type, R>> for $type {
+ fn from(val: FieldValue<$type, R>) -> $type {
+ val.value
+ }
+ }
+ };
+}
+
+FieldValue_impl_for!(u8);
+FieldValue_impl_for!(u16);
+FieldValue_impl_for!(u32);
+FieldValue_impl_for!(u64);
+FieldValue_impl_for!(u128);
+FieldValue_impl_for!(usize);
+
+impl<T: UIntLike, R: RegisterLongName> FieldValue<T, R> {
+ #[inline]
+ pub fn none() -> Self {
+ Self {
+ mask: T::zero(),
+ value: T::zero(),
+ associated_register: PhantomData,
+ }
+ }
+
+ /// Get the raw bitmask represented by this FieldValue.
+ #[inline]
+ pub const fn mask(&self) -> T {
+ self.mask as T
+ }
+
+ #[inline]
+ pub fn read(&self, field: Field<T, R>) -> T {
+ field.read(self.value)
+ }
+
+ /// Modify fields in a register value
+ #[inline]
+ pub fn modify(self, val: T) -> T {
+ (val & !self.mask) | self.value
+ }
+
+ /// Check if any specified parts of a field match
+ #[inline]
+ pub fn matches_any(&self, val: T) -> bool {
+ val & self.mask != T::zero()
+ }
+
+ /// Check if all specified parts of a field match
+ #[inline]
+ pub fn matches_all(&self, val: T) -> bool {
+ val & self.mask == self.value
+ }
+}
+
+// Combine two fields with the addition operator
+impl<T: UIntLike, R: RegisterLongName> Add for FieldValue<T, R> {
+ type Output = Self;
+
+ #[inline]
+ fn add(self, rhs: Self) -> Self {
+ FieldValue {
+ mask: self.mask | rhs.mask,
+ value: self.value | rhs.value,
+ associated_register: PhantomData,
+ }
+ }
+}
+
+// Combine two fields with the += operator
+impl<T: UIntLike, R: RegisterLongName> AddAssign for FieldValue<T, R> {
+ #[inline]
+ fn add_assign(&mut self, rhs: FieldValue<T, R>) {
+ self.mask |= rhs.mask;
+ self.value |= rhs.value;
+ }
+}
+
+/// Conversion of raw register value into enumerated values member.
+/// Implemented inside register_bitfields! macro for each bit field.
+pub trait TryFromValue<V> {
+ type EnumType;
+
+ fn try_from_value(v: V) -> Option<Self::EnumType>;
+}
+
+/// Helper macro for computing bitmask of variable number of bits
+#[macro_export]
+macro_rules! bitmask {
+ ($numbits:expr) => {
+ (1 << ($numbits - 1)) + ((1 << ($numbits - 1)) - 1)
+ };
+}
+
+/// Helper macro for defining register fields.
+#[macro_export]
+macro_rules! register_bitmasks {
+ {
+ // BITFIELD_NAME OFFSET(x)
+ $(#[$outer:meta])*
+ $valtype:ident, $reg_desc:ident, [
+ $( $(#[$inner:meta])* $field:ident OFFSET($offset:expr)),+ $(,)?
+ ]
+ } => {
+ $(#[$outer])*
+ $( $crate::register_bitmasks!($valtype, $reg_desc, $(#[$inner])* $field, $offset, 1, []); )*
+ };
+ {
+ // BITFIELD_NAME OFFSET
+ // All fields are 1 bit
+ $(#[$outer:meta])*
+ $valtype:ident, $reg_desc:ident, [
+ $( $(#[$inner:meta])* $field:ident $offset:expr ),+ $(,)?
+ ]
+ } => {
+ $(#[$outer])*
+ $( $crate::register_bitmasks!($valtype, $reg_desc, $(#[$inner])* $field, $offset, 1, []); )*
+ };
+
+ {
+ // BITFIELD_NAME OFFSET(x) NUMBITS(y)
+ $(#[$outer:meta])*
+ $valtype:ident, $reg_desc:ident, [
+ $( $(#[$inner:meta])* $field:ident OFFSET($offset:expr) NUMBITS($numbits:expr) ),+ $(,)?
+ ]
+ } => {
+ $(#[$outer])*
+ $( $crate::register_bitmasks!($valtype, $reg_desc, $(#[$inner])* $field, $offset, $numbits, []); )*
+ };
+
+ {
+ // BITFIELD_NAME OFFSET(x) NUMBITS(y) []
+ $(#[$outer:meta])*
+ $valtype:ident, $reg_desc:ident, [
+ $( $(#[$inner:meta])* $field:ident OFFSET($offset:expr) NUMBITS($numbits:expr)
+ $values:tt ),+ $(,)?
+ ]
+ } => {
+ $(#[$outer])*
+ $( $crate::register_bitmasks!($valtype, $reg_desc, $(#[$inner])* $field, $offset, $numbits,
+ $values); )*
+ };
+ {
+ $valtype:ident, $reg_desc:ident, $(#[$outer:meta])* $field:ident,
+ $offset:expr, $numbits:expr,
+ [$( $(#[$inner:meta])* $valname:ident = $value:expr ),+ $(,)?]
+ } => { // this match arm is duplicated below with an allowance for 0 elements in the valname -> value array,
+ // to seperately support the case of zero-variant enums not supporting non-default
+ // representations.
+ #[allow(non_upper_case_globals)]
+ #[allow(unused)]
+ pub const $field: Field<$valtype, $reg_desc> =
+ Field::<$valtype, $reg_desc>::new($crate::bitmask!($numbits), $offset);
+
+ #[allow(non_snake_case)]
+ #[allow(unused)]
+ $(#[$outer])*
+ pub mod $field {
+ #[allow(unused_imports)]
+ use $crate::fields::{TryFromValue, FieldValue};
+ use super::$reg_desc;
+
+ $(
+ #[allow(non_upper_case_globals)]
+ #[allow(unused)]
+ $(#[$inner])*
+ pub const $valname: FieldValue<$valtype, $reg_desc> =
+ FieldValue::<$valtype, $reg_desc>::new($crate::bitmask!($numbits),
+ $offset, $value);
+ )*
+
+ #[allow(non_upper_case_globals)]
+ #[allow(unused)]
+ pub const SET: FieldValue<$valtype, $reg_desc> =
+ FieldValue::<$valtype, $reg_desc>::new($crate::bitmask!($numbits),
+ $offset, $crate::bitmask!($numbits));
+
+ #[allow(non_upper_case_globals)]
+ #[allow(unused)]
+ pub const CLEAR: FieldValue<$valtype, $reg_desc> =
+ FieldValue::<$valtype, $reg_desc>::new($crate::bitmask!($numbits),
+ $offset, 0);
+
+ #[allow(dead_code)]
+ #[allow(non_camel_case_types)]
+ #[derive(Copy, Clone, Eq, PartialEq)]
+ #[repr($valtype)] // so that values larger than isize::MAX can be stored
+ $(#[$outer])*
+ pub enum Value {
+ $(
+ $(#[$inner])*
+ $valname = $value,
+ )*
+ }
+
+ impl TryFromValue<$valtype> for Value {
+ type EnumType = Value;
+
+ fn try_from_value(v: $valtype) -> Option<Self::EnumType> {
+ match v {
+ $(
+ $(#[$inner])*
+ x if x == Value::$valname as $valtype => Some(Value::$valname),
+ )*
+
+ _ => Option::None
+ }
+ }
+ }
+
+ impl From<Value> for FieldValue<$valtype, $reg_desc> {
+ fn from(v: Value) -> Self {
+ Self::new($crate::bitmask!($numbits), $offset, v as $valtype)
+ }
+ }
+ }
+ };
+ {
+ $valtype:ident, $reg_desc:ident, $(#[$outer:meta])* $field:ident,
+ $offset:expr, $numbits:expr,
+ []
+ } => { //same pattern as previous match arm, for 0 elements in array. Removes code associated with array.
+ #[allow(non_upper_case_globals)]
+ #[allow(unused)]
+ pub const $field: Field<$valtype, $reg_desc> =
+ Field::<$valtype, $reg_desc>::new($crate::bitmask!($numbits), $offset);
+
+ #[allow(non_snake_case)]
+ #[allow(unused)]
+ $(#[$outer])*
+ pub mod $field {
+ #[allow(unused_imports)]
+ use $crate::fields::{FieldValue, TryFromValue};
+ use super::$reg_desc;
+
+ #[allow(non_upper_case_globals)]
+ #[allow(unused)]
+ pub const SET: FieldValue<$valtype, $reg_desc> =
+ FieldValue::<$valtype, $reg_desc>::new($crate::bitmask!($numbits),
+ $offset, $crate::bitmask!($numbits));
+
+ #[allow(non_upper_case_globals)]
+ #[allow(unused)]
+ pub const CLEAR: FieldValue<$valtype, $reg_desc> =
+ FieldValue::<$valtype, $reg_desc>::new($crate::bitmask!($numbits),
+ $offset, 0);
+
+ #[allow(dead_code)]
+ #[allow(non_camel_case_types)]
+ $(#[$outer])*
+ pub enum Value {}
+
+ impl TryFromValue<$valtype> for Value {
+ type EnumType = Value;
+
+ fn try_from_value(_v: $valtype) -> Option<Self::EnumType> {
+ Option::None
+ }
+ }
+ }
+ };
+}
+
+/// Define register types and fields.
+#[macro_export]
+macro_rules! register_bitfields {
+ {
+ $valtype:ident, $( $(#[$inner:meta])* $vis:vis $reg:ident $fields:tt ),* $(,)?
+ } => {
+ $(
+ #[allow(non_snake_case)]
+ $(#[$inner])*
+ $vis mod $reg {
+ // Visibility note: This is left always `pub` as it is not
+ // meaningful to restrict access to the `Register` element of
+ // the register module if the module itself is in scope
+ //
+ // (if you can access $reg, you can access $reg::Register)
+ #[derive(Clone, Copy)]
+ pub struct Register;
+ impl $crate::RegisterLongName for Register {}
+
+ use $crate::fields::Field;
+
+ $crate::register_bitmasks!( $valtype, Register, $fields );
+ }
+ )*
+ }
+}
+
+#[cfg(feature = "std_unit_tests")]
+#[cfg(test)]
+mod tests {
+ #[derive(Debug, PartialEq, Eq)]
+ enum Foo {
+ Foo0,
+ Foo1,
+ Foo2,
+ Foo3,
+ Foo4,
+ Foo5,
+ Foo6,
+ Foo7,
+ }
+
+ impl crate::fields::TryFromValue<u16> for Foo {
+ type EnumType = Foo;
+
+ fn try_from_value(v: u16) -> Option<Self::EnumType> {
+ Self::try_from_value(v as u32)
+ }
+ }
+ impl crate::fields::TryFromValue<u32> for Foo {
+ type EnumType = Foo;
+
+ fn try_from_value(v: u32) -> Option<Self::EnumType> {
+ match v {
+ 0 => Some(Foo::Foo0),
+ 1 => Some(Foo::Foo1),
+ 2 => Some(Foo::Foo2),
+ 3 => Some(Foo::Foo3),
+ 4 => Some(Foo::Foo4),
+ 5 => Some(Foo::Foo5),
+ 6 => Some(Foo::Foo6),
+ 7 => Some(Foo::Foo7),
+ _ => None,
+ }
+ }
+ }
+
+ mod field {
+ use super::Foo;
+ use crate::fields::{Field, TryFromValue};
+
+ #[test]
+ fn test_new() {
+ let field8 = Field::<u8, ()>::new(0x12, 3);
+ assert_eq!(field8.mask, 0x12_u8);
+ assert_eq!(field8.shift, 3);
+ let field16 = Field::<u16, ()>::new(0x1234, 5);
+ assert_eq!(field16.mask, 0x1234_u16);
+ assert_eq!(field16.shift, 5);
+ let field32 = Field::<u32, ()>::new(0x12345678, 9);
+ assert_eq!(field32.mask, 0x12345678_u32);
+ assert_eq!(field32.shift, 9);
+ let field64 = Field::<u64, ()>::new(0x12345678_9abcdef0, 1);
+ assert_eq!(field64.mask, 0x12345678_9abcdef0_u64);
+ assert_eq!(field64.shift, 1);
+ let field128 = Field::<u128, ()>::new(0x12345678_9abcdef0_0fedcba9_87654321, 1);
+ assert_eq!(field128.mask, 0x12345678_9abcdef0_0fedcba9_87654321_u128);
+ assert_eq!(field128.shift, 1);
+ }
+
+ #[test]
+ fn test_read() {
+ let field = Field::<u32, ()>::new(0xFF, 4);
+ assert_eq!(field.read(0x123), 0x12);
+ let field = Field::<u32, ()>::new(0xF0F, 4);
+ assert_eq!(field.read(0x1234), 0x103);
+ }
+
+ #[test]
+ fn test_is_set() {
+ let field = Field::<u16, ()>::new(0xFF, 4);
+ assert_eq!(field.is_set(0), false);
+ assert_eq!(field.is_set(0xFFFF), true);
+ assert_eq!(field.is_set(0x0FF0), true);
+ assert_eq!(field.is_set(0x1000), false);
+ assert_eq!(field.is_set(0x0100), true);
+ assert_eq!(field.is_set(0x0010), true);
+ assert_eq!(field.is_set(0x0001), false);
+
+ for shift in 0..24 {
+ let field = Field::<u32, ()>::new(0xFF, shift);
+ for x in 1..=0xFF {
+ assert_eq!(field.is_set(x << shift), true);
+ }
+ assert_eq!(field.is_set(!(0xFF << shift)), false);
+ }
+ }
+
+ #[test]
+ fn test_read_as_enum() {
+ let field = Field::<u16, ()>::new(0x7, 4);
+ assert_eq!(field.read_as_enum(0x1234), Some(Foo::Foo3));
+ assert_eq!(field.read_as_enum(0x5678), Some(Foo::Foo7));
+ assert_eq!(field.read_as_enum(0xFFFF), Some(Foo::Foo7));
+ assert_eq!(field.read_as_enum(0x0000), Some(Foo::Foo0));
+ assert_eq!(field.read_as_enum(0x0010), Some(Foo::Foo1));
+ assert_eq!(field.read_as_enum(0x1204), Some(Foo::Foo0));
+
+ for shift in 0..29 {
+ let field = Field::<u32, ()>::new(0x7, shift);
+ for x in 0..8 {
+ assert_eq!(field.read_as_enum(x << shift), Foo::try_from_value(x));
+ }
+ }
+ }
+ }
+
+ mod field_value {
+ use crate::fields::Field;
+
+ #[test]
+ fn test_from() {
+ let field = Field::<u32, ()>::new(0xFF, 4);
+ assert_eq!(u32::from(field.val(0)), 0);
+ assert_eq!(u32::from(field.val(0xFFFFFFFF)), 0xFF0);
+ assert_eq!(u32::from(field.val(0x12)), 0x120);
+ assert_eq!(u32::from(field.val(0x123)), 0x230);
+
+ for shift in 0..32 {
+ let field = Field::<u32, ()>::new(0xFF, shift);
+ for x in 0..=0xFF {
+ assert_eq!(u32::from(field.val(x)), x << shift);
+ }
+ }
+ }
+
+ #[test]
+ fn test_read_same_field() {
+ let field = Field::<u32, ()>::new(0xFF, 4);
+ assert_eq!(field.val(0).read(field), 0);
+ assert_eq!(field.val(0xFFFFFFFF).read(field), 0xFF);
+ assert_eq!(field.val(0x12).read(field), 0x12);
+ assert_eq!(field.val(0x123).read(field), 0x23);
+
+ for shift in 0..24 {
+ let field = Field::<u32, ()>::new(0xFF, shift);
+ for x in 0..=0xFF {
+ assert_eq!(field.val(x).read(field), x);
+ }
+ }
+ }
+
+ #[test]
+ fn test_read_disjoint_fields() {
+ for shift in 0..24 {
+ let field1 = Field::<u32, ()>::new(0xF0, shift);
+ let field2 = Field::<u32, ()>::new(0x0F, shift);
+ for x in 0..=0xFF {
+ assert_eq!(field1.val(x).read(field2), 0);
+ assert_eq!(field2.val(x).read(field1), 0);
+ }
+ }
+ for shift in 0..24 {
+ let field1 = Field::<u32, ()>::new(0xF, shift);
+ let field2 = Field::<u32, ()>::new(0xF, shift + 4);
+ for x in 0..=0xFF {
+ assert_eq!(field1.val(x).read(field2), 0);
+ assert_eq!(field2.val(x).read(field1), 0);
+ }
+ }
+ }
+
+ #[test]
+ fn test_modify() {
+ let field = Field::<u32, ()>::new(0xFF, 4);
+ assert_eq!(field.val(0x23).modify(0x0000), 0x0230);
+ assert_eq!(field.val(0x23).modify(0xFFFF), 0xF23F);
+ assert_eq!(field.val(0x23).modify(0x1234), 0x1234);
+ assert_eq!(field.val(0x23).modify(0x5678), 0x5238);
+ }
+
+ #[test]
+ fn test_matches_any() {
+ let field = Field::<u32, ()>::new(0xFF, 4);
+ assert_eq!(field.val(0x23).matches_any(0x1234), true);
+ assert_eq!(field.val(0x23).matches_any(0x5678), true);
+ assert_eq!(field.val(0x23).matches_any(0x5008), false);
+
+ for shift in 0..24 {
+ let field = Field::<u32, ()>::new(0xFF, shift);
+ for x in 0..=0xFF {
+ let field_value = field.val(x);
+ for y in 1..=0xFF {
+ assert_eq!(field_value.matches_any(y << shift), true);
+ }
+ assert_eq!(field_value.matches_any(0), false);
+ assert_eq!(field_value.matches_any(!(0xFF << shift)), false);
+ }
+ }
+ }
+
+ #[test]
+ fn test_matches_all() {
+ let field = Field::<u32, ()>::new(0xFF, 4);
+ assert_eq!(field.val(0x23).matches_all(0x1234), true);
+ assert_eq!(field.val(0x23).matches_all(0x5678), false);
+
+ for shift in 0..24 {
+ let field = Field::<u32, ()>::new(0xFF, shift);
+ for x in 0..=0xFF {
+ assert_eq!(field.val(x).matches_all(x << shift), true);
+ assert_eq!(field.val(x + 1).matches_all(x << shift), false);
+ }
+ }
+ }
+
+ #[test]
+ fn test_add_disjoint_fields() {
+ let field1 = Field::<u32, ()>::new(0xFF, 24);
+ let field2 = Field::<u32, ()>::new(0xFF, 16);
+ let field3 = Field::<u32, ()>::new(0xFF, 8);
+ let field4 = Field::<u32, ()>::new(0xFF, 0);
+ assert_eq!(
+ u32::from(
+ field1.val(0x12) + field2.val(0x34) + field3.val(0x56) + field4.val(0x78)
+ ),
+ 0x12345678
+ );
+
+ for shift in 0..24 {
+ let field1 = Field::<u32, ()>::new(0xF, shift);
+ let field2 = Field::<u32, ()>::new(0xF, shift + 4);
+ for x in 0..=0xF {
+ for y in 0..=0xF {
+ assert_eq!(
+ u32::from(field1.val(x) + field2.val(y)),
+ (x | (y << 4)) << shift
+ );
+ }
+ }
+ }
+ }
+
+ #[test]
+ fn test_add_assign_disjoint_fields() {
+ let field1 = Field::<u32, ()>::new(0xFF, 24);
+ let field2 = Field::<u32, ()>::new(0xFF, 16);
+ let field3 = Field::<u32, ()>::new(0xFF, 8);
+ let field4 = Field::<u32, ()>::new(0xFF, 0);
+
+ let mut value = field1.val(0x12);
+ value += field2.val(0x34);
+ value += field3.val(0x56);
+ value += field4.val(0x78);
+ assert_eq!(u32::from(value), 0x12345678);
+
+ for shift in 0..24 {
+ let field1 = Field::<u32, ()>::new(0xF, shift);
+ let field2 = Field::<u32, ()>::new(0xF, shift + 4);
+ for x in 0..=0xF {
+ for y in 0..=0xF {
+ let mut value = field1.val(x);
+ value += field2.val(y);
+ assert_eq!(u32::from(value), (x | (y << 4)) << shift);
+ }
+ }
+ }
+ }
+ }
+
+ // TODO: More unit tests here.
+}
diff --git a/src/interfaces.rs b/src/interfaces.rs
new file mode 100644
index 0000000..dbd252a
--- /dev/null
+++ b/src/interfaces.rs
@@ -0,0 +1,309 @@
+//! Interfaces (traits) to register types
+//!
+//! This module contains traits which reflect standardized interfaces
+//! to different types of registers. Examples of registers
+//! implementing these interfaces are [`ReadWrite`](crate::registers::ReadWrite) or
+//! [`InMemoryRegister`](crate::registers::InMemoryRegister).
+//!
+//! Each trait has two associated type parameters, namely:
+//!
+//! - `T`: [`UIntLike`](crate::UIntLike), indicating the underlying
+//! integer type used to represent the register's raw contents.
+//!
+//! - `R`: [`RegisterLongName`](crate::RegisterLongName), functioning
+//! as a type to identify this register's descriptive name and
+//! semantic meaning. It is further used to impose type constraints
+//! on values passed through the API, such as
+//! [`FieldValue`](crate::fields::FieldValue).
+//!
+//! Registers can have different access levels, which are mapped to
+//! different traits respectively:
+//!
+//! - [`Readable`]: indicates that the current value of this register
+//! can be read. Implementations will need to provide the
+//! [`get`](crate::interfaces::Readable::get) method.
+//!
+//! - [`Writeable`]: indicates that the value of this register can be
+//! set. Implementations will need to provide the
+//! [`set`](crate::interfaces::Writeable::set) method.
+//!
+//! - [`ReadWriteable`]: indicates that this register can be
+//! _modified_. It is not sufficient for registers to be both read-
+//! and writable, they must also have the same semantic meaning when
+//! read from and written to. This is not true in general, for
+//! example a memory-mapped UART register might transmit when
+//! writing and receive when reading.
+//!
+//! If a type implements both [`Readable`] and [`Writeable`], and
+//! the associated [`RegisterLongName`](crate::RegisterLongName)
+//! type parameters are identical, it will automatically implement
+//! [`ReadWriteable`]. In particular, for
+//! [`Aliased`](crate::registers::Aliased) this is -- in general --
+//! not the case, so
+//!
+//! ```rust
+//! # use tock_registers::interfaces::{Readable, Writeable, ReadWriteable};
+//! # use tock_registers::registers::ReadWrite;
+//! # use tock_registers::register_bitfields;
+//! register_bitfields![u8,
+//! A [
+//! DUMMY OFFSET(0) NUMBITS(1) [],
+//! ],
+//! ];
+//! let read_write_reg: &ReadWrite<u8, A::Register> = unsafe {
+//! core::mem::transmute(Box::leak(Box::new(0_u8)))
+//! };
+//! ReadWriteable::modify(read_write_reg, A::DUMMY::SET);
+//! ```
+//!
+//! works, but not
+//!
+//! ```compile_fail
+//! # use tock_registers::interfaces::{Readable, Writeable, ReadWriteable};
+//! # use tock_registers::registers::Aliased;
+//! # use tock_registers::register_bitfields;
+//! register_bitfields![u8,
+//! A [
+//! DUMMY OFFSET(0) NUMBITS(1) [],
+//! ],
+//! B [
+//! DUMMY OFFSET(0) NUMBITS(1) [],
+//! ],
+//! ];
+//! let aliased_reg: &Aliased<u8, A::Register, B::Register> = unsafe {
+//! core::mem::transmute(Box::leak(Box::new(0_u8)))
+//! };
+//! ReadWriteable::modify(aliased_reg, A::DUMMY::SET);
+//! ```
+//!
+//! ## Example: implementing a custom register type
+//!
+//! These traits can be used to implement custom register types, which
+//! are compatible to the ones shipped in this crate. For example, to
+//! define a register which sets a `u8` value using a Cell reference,
+//! always reads the bitwise-negated vale and prints every written
+//! value to the console:
+//!
+//! ```rust
+//! # use core::cell::Cell;
+//! # use core::marker::PhantomData;
+//! #
+//! # use tock_registers::interfaces::{Readable, Writeable, ReadWriteable};
+//! # use tock_registers::RegisterLongName;
+//! # use tock_registers::register_bitfields;
+//! #
+//! struct DummyRegister<'a, R: RegisterLongName> {
+//! cell_ref: &'a Cell<u8>,
+//! _register_long_name: PhantomData<R>,
+//! }
+//!
+//! impl<'a, R: RegisterLongName> Readable for DummyRegister<'a, R> {
+//! type T = u8;
+//! type R = R;
+//!
+//! fn get(&self) -> u8 {
+//! // Return the bitwise-inverse of the current value
+//! !self.cell_ref.get()
+//! }
+//! }
+//!
+//! impl<'a, R: RegisterLongName> Writeable for DummyRegister<'a, R> {
+//! type T = u8;
+//! type R = R;
+//!
+//! fn set(&self, value: u8) {
+//! println!("Setting Cell to {:02x?}!", value);
+//! self.cell_ref.set(value);
+//! }
+//! }
+//!
+//! register_bitfields![u8,
+//! DummyReg [
+//! HIGH OFFSET(4) NUMBITS(4) [
+//! A = 0b0001,
+//! B = 0b0010,
+//! C = 0b0100,
+//! D = 0b1000,
+//! ],
+//! LOW OFFSET(0) NUMBITS(4) [],
+//! ],
+//! ];
+//!
+//! // Create a new DummyRegister over some Cell<u8>
+//! let cell = Cell::new(0);
+//! let dummy = DummyRegister {
+//! cell_ref: &cell,
+//! _register_long_name: PhantomData,
+//! };
+//!
+//! // Set a value and read it back. This demonstrates the raw getters
+//! // and setters of Writeable and Readable
+//! dummy.set(0xFA);
+//! assert!(dummy.get() == 0x05);
+//!
+//! // Use some of the automatically derived APIs, such as
+//! // ReadWriteable::modify and Readable::read
+//! dummy.modify(DummyReg::HIGH::C);
+//! assert!(dummy.read(DummyReg::HIGH) == 0xb);
+//! ```
+
+use crate::fields::{Field, FieldValue, TryFromValue};
+use crate::{LocalRegisterCopy, RegisterLongName, UIntLike};
+
+/// Readable register
+///
+/// Register which at least supports reading the current value. Only
+/// [`Readable::get`] must be implemented, as for other methods a
+/// default implementation is provided.
+///
+/// A register that is both [`Readable`] and [`Writeable`] will also
+/// automatically be [`ReadWriteable`], if the [`RegisterLongName`] of
+/// [`Readable`] is the same as that of [`Writeable`] (i.e. not for
+/// [`Aliased`](crate::registers::Aliased) registers).
+pub trait Readable {
+ type T: UIntLike;
+ type R: RegisterLongName;
+
+ /// Get the raw register value
+ fn get(&self) -> Self::T;
+
+ #[inline]
+ /// Read the value of the given field
+ fn read(&self, field: Field<Self::T, Self::R>) -> Self::T {
+ field.read(self.get())
+ }
+
+ /// Set the raw register value
+ ///
+ /// The [`register_bitfields!`](crate::register_bitfields) macro will
+ /// generate an enum containing the various named field variants and
+ /// implementing the required [`TryFromValue`] trait. It is accessible as
+ /// `$REGISTER_NAME::$FIELD_NAME::Value`.
+ ///
+ /// This method can be useful to symbolically represent read register field
+ /// states throughout the codebase and to enforce exhaustive matches over
+ /// all defined valid register field values.
+ ///
+ /// ## Usage Example
+ ///
+ /// ```rust
+ /// # use tock_registers::interfaces::Readable;
+ /// # use tock_registers::registers::InMemoryRegister;
+ /// # use tock_registers::register_bitfields;
+ /// register_bitfields![u8,
+ /// EXAMPLEREG [
+ /// TESTFIELD OFFSET(0) NUMBITS(2) [
+ /// Foo = 0,
+ /// Bar = 1,
+ /// Baz = 2,
+ /// ],
+ /// ],
+ /// ];
+ ///
+ /// let reg: InMemoryRegister<u8, EXAMPLEREG::Register> =
+ /// InMemoryRegister::new(2);
+ ///
+ /// match reg.read_as_enum(EXAMPLEREG::TESTFIELD) {
+ /// Some(EXAMPLEREG::TESTFIELD::Value::Foo) => "Tock",
+ /// Some(EXAMPLEREG::TESTFIELD::Value::Bar) => "is",
+ /// Some(EXAMPLEREG::TESTFIELD::Value::Baz) => "awesome!",
+ /// None => panic!("boo!"),
+ /// };
+ /// ```
+ #[inline]
+ fn read_as_enum<E: TryFromValue<Self::T, EnumType = E>>(
+ &self,
+ field: Field<Self::T, Self::R>,
+ ) -> Option<E> {
+ field.read_as_enum(self.get())
+ }
+
+ #[inline]
+ /// Make a local copy of the register
+ fn extract(&self) -> LocalRegisterCopy<Self::T, Self::R> {
+ LocalRegisterCopy::new(self.get())
+ }
+
+ #[inline]
+ /// Check if one or more bits in a field are set
+ fn is_set(&self, field: Field<Self::T, Self::R>) -> bool {
+ field.is_set(self.get())
+ }
+
+ #[inline]
+ /// Check if any specified parts of a field match
+ fn matches_any(&self, field: FieldValue<Self::T, Self::R>) -> bool {
+ field.matches_any(self.get())
+ }
+
+ #[inline]
+ /// Check if all specified parts of a field match
+ fn matches_all(&self, field: FieldValue<Self::T, Self::R>) -> bool {
+ field.matches_all(self.get())
+ }
+}
+
+/// Writeable register
+///
+/// Register which at least supports setting a value. Only
+/// [`Writeable::set`] must be implemented, as for other methods a
+/// default implementation is provided.
+///
+/// A register that is both [`Readable`] and [`Writeable`] will also
+/// automatically be [`ReadWriteable`], if the [`RegisterLongName`] of
+/// [`Readable`] is the same as that of [`Writeable`] (i.e. not for
+/// [`Aliased`](crate::registers::Aliased) registers).
+pub trait Writeable {
+ type T: UIntLike;
+ type R: RegisterLongName;
+
+ /// Set the raw register value
+ fn set(&self, value: Self::T);
+
+ #[inline]
+ /// Write the value of one or more fields, overwriting the other fields with zero
+ fn write(&self, field: FieldValue<Self::T, Self::R>) {
+ self.set(field.value);
+ }
+
+ #[inline]
+ /// Write the value of one or more fields, maintaining the value of unchanged fields via a
+ /// provided original value, rather than a register read.
+ fn modify_no_read(
+ &self,
+ original: LocalRegisterCopy<Self::T, Self::R>,
+ field: FieldValue<Self::T, Self::R>,
+ ) {
+ self.set(field.modify(original.get()));
+ }
+}
+
+/// [`Readable`] and [`Writeable`] register, over the same
+/// [`RegisterLongName`]
+///
+/// Register which supports both reading and setting a value.
+///
+/// **This trait does not have to be implemented manually!** It is
+/// automatically implemented for every type that is both [`Readable`]
+/// and [`Writeable`], as long as [`Readable::R`] == [`Writeable::R`]
+/// (i.e. not for [`Aliased`](crate::registers::Aliased) registers).
+pub trait ReadWriteable {
+ type T: UIntLike;
+ type R: RegisterLongName;
+
+ /// Write the value of one or more fields, leaving the other fields unchanged
+ fn modify(&self, field: FieldValue<Self::T, Self::R>);
+}
+
+impl<T: UIntLike, R: RegisterLongName, S> ReadWriteable for S
+where
+ S: Readable<T = T, R = R> + Writeable<T = T, R = R>,
+{
+ type T = T;
+ type R = R;
+
+ #[inline]
+ fn modify(&self, field: FieldValue<Self::T, Self::R>) {
+ self.set(field.modify(self.get()));
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..ecc7a09
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,128 @@
+//! Tock Register Interface
+//!
+//! Provides efficient mechanisms to express and use type-checked
+//! memory mapped registers and bitfields.
+//!
+//! ```rust
+//! # fn main() {}
+//!
+//! use tock_registers::registers::{ReadOnly, ReadWrite};
+//! use tock_registers::register_bitfields;
+//!
+//! // Register maps are specified like this:
+//! #[repr(C)]
+//! struct Registers {
+//! // Control register: read-write
+//! cr: ReadWrite<u32, Control::Register>,
+//! // Status register: read-only
+//! s: ReadOnly<u32, Status::Register>,
+//! }
+//!
+//! // Register fields and definitions look like this:
+//! register_bitfields![u32,
+//! // Simpler bitfields are expressed concisely:
+//! Control [
+//! /// Stop the Current Transfer
+//! STOP 8,
+//! /// Software Reset
+//! SWRST 7,
+//! /// Master Disable
+//! MDIS 1,
+//! /// Master Enable
+//! MEN 0
+//! ],
+//!
+//! // More complex registers can express subtypes:
+//! Status [
+//! TXCOMPLETE OFFSET(0) NUMBITS(1) [],
+//! TXINTERRUPT OFFSET(1) NUMBITS(1) [],
+//! RXCOMPLETE OFFSET(2) NUMBITS(1) [],
+//! RXINTERRUPT OFFSET(3) NUMBITS(1) [],
+//! MODE OFFSET(4) NUMBITS(3) [
+//! FullDuplex = 0,
+//! HalfDuplex = 1,
+//! Loopback = 2,
+//! Disabled = 3
+//! ],
+//! ERRORCOUNT OFFSET(6) NUMBITS(3) []
+//! ]
+//! ];
+//! ```
+//!
+//! Author
+//! ------
+//! - Shane Leonard <shanel@stanford.edu>
+
+#![no_std]
+// If we don't build any actual register types, we don't need unsafe
+// code in this crate
+#![cfg_attr(not(feature = "register_types"), forbid(unsafe_code))]
+
+pub mod fields;
+pub mod interfaces;
+pub mod macros;
+
+#[cfg(feature = "register_types")]
+pub mod registers;
+
+mod local_register;
+pub use local_register::LocalRegisterCopy;
+
+use core::ops::{BitAnd, BitOr, BitOrAssign, Not, Shl, Shr};
+
+/// Trait representing the base type of registers.
+///
+/// UIntLike defines basic properties of types required to
+/// read/write/modify a register through its methods and supertrait
+/// requirements.
+///
+/// It features a range of default implementations for common unsigned
+/// integer types, such as [`u8`], [`u16`], [`u32`], [`u64`], [`u128`],
+/// and [`usize`].
+pub trait UIntLike:
+ BitAnd<Output = Self>
+ + BitOr<Output = Self>
+ + BitOrAssign
+ + Not<Output = Self>
+ + Eq
+ + Shr<usize, Output = Self>
+ + Shl<usize, Output = Self>
+ + Copy
+ + Clone
+{
+ /// Return the representation of the value `0` in the implementing
+ /// type.
+ ///
+ /// This can be used to acquire values of the [`UIntLike`] type,
+ /// even in generic implementations. For instance, to get the
+ /// value `1`, one can use `<T as UIntLike>::zero() + 1`. To get
+ /// the largest representable value, use a bitwise negation: `~(<T
+ /// as UIntLike>::zero())`.
+ fn zero() -> Self;
+}
+
+// Helper macro for implementing the UIntLike trait on differrent
+// types.
+macro_rules! UIntLike_impl_for {
+ ($type:ty) => {
+ impl UIntLike for $type {
+ fn zero() -> Self {
+ 0
+ }
+ }
+ };
+}
+
+UIntLike_impl_for!(u8);
+UIntLike_impl_for!(u16);
+UIntLike_impl_for!(u32);
+UIntLike_impl_for!(u64);
+UIntLike_impl_for!(u128);
+UIntLike_impl_for!(usize);
+
+/// Descriptive name for each register.
+pub trait RegisterLongName {}
+
+// Useful implementation for when no RegisterLongName is required
+// (e.g. no fields need to be accessed, just the raw register values)
+impl RegisterLongName for () {}
diff --git a/src/local_register.rs b/src/local_register.rs
new file mode 100644
index 0000000..15bf7d4
--- /dev/null
+++ b/src/local_register.rs
@@ -0,0 +1,129 @@
+//! Module containing the [`LocalRegisterCopy`] type. Please refer to
+//! its documentation.
+
+use core::fmt;
+use core::marker::PhantomData;
+
+use crate::fields::{Field, FieldValue, TryFromValue};
+use crate::{RegisterLongName, UIntLike};
+
+/// A read-write copy of register contents.
+///
+/// This behaves very similarly to a read-write register, but instead of doing a
+/// volatile read to MMIO to get the value for each function call, a copy of the
+/// register contents are stored locally in memory. This allows a peripheral
+/// to do a single read on a register, and then check which bits are set without
+/// having to do a full MMIO read each time. It also allows the value of the
+/// register to be "cached" in case the peripheral driver needs to clear the
+/// register in hardware yet still be able to check the bits.
+/// You can write to a local register, which will modify the stored value, but
+/// will not modify any hardware because it operates only on local copy.
+///
+/// This type does not implement the
+/// [`Readable`](crate::interfaces::Readable) and
+/// [`Writeable`](crate::interfaces::Writeable) traits because it
+/// requires a mutable reference to modify the contained value. It
+/// still mirrors the interface which would be exposed by a type
+/// implementing [`Readable`](crate::interfaces::Readable),
+/// [`Writeable`](crate::interfaces::Writeable) and
+/// [`ReadWriteable`](crate::interfaces::ReadWriteable).
+#[derive(Copy, Clone)]
+pub struct LocalRegisterCopy<T: UIntLike, R: RegisterLongName = ()> {
+ value: T,
+ associated_register: PhantomData<R>,
+}
+
+impl<T: UIntLike, R: RegisterLongName> LocalRegisterCopy<T, R> {
+ pub const fn new(value: T) -> Self {
+ LocalRegisterCopy {
+ value: value,
+ associated_register: PhantomData,
+ }
+ }
+
+ /// Get the raw register value
+ #[inline]
+ pub fn get(&self) -> T {
+ self.value
+ }
+
+ /// Set the raw register value
+ #[inline]
+ pub fn set(&mut self, value: T) {
+ self.value = value;
+ }
+
+ /// Read the value of the given field
+ #[inline]
+ pub fn read(&self, field: Field<T, R>) -> T {
+ field.read(self.get())
+ }
+
+ /// Read value of the given field as an enum member
+ #[inline]
+ pub fn read_as_enum<E: TryFromValue<T, EnumType = E>>(&self, field: Field<T, R>) -> Option<E> {
+ field.read_as_enum(self.get())
+ }
+
+ /// Write the value of one or more fields, overwriting the other fields with zero
+ #[inline]
+ pub fn write(&mut self, field: FieldValue<T, R>) {
+ self.set(field.value);
+ }
+
+ /// Write the value of one or more fields, leaving the other fields unchanged
+ #[inline]
+ pub fn modify(&mut self, field: FieldValue<T, R>) {
+ self.set(field.modify(self.get()));
+ }
+
+ /// Check if one or more bits in a field are set
+ #[inline]
+ pub fn is_set(&self, field: Field<T, R>) -> bool {
+ field.is_set(self.get())
+ }
+
+ /// Check if any specified parts of a field match
+ #[inline]
+ pub fn matches_any(&self, field: FieldValue<T, R>) -> bool {
+ field.matches_any(self.get())
+ }
+
+ /// Check if all specified parts of a field match
+ #[inline]
+ pub fn matches_all(&self, field: FieldValue<T, R>) -> bool {
+ field.matches_all(self.get())
+ }
+
+ /// Do a bitwise AND operation of the stored value and the passed in value
+ /// and return a new LocalRegisterCopy.
+ #[inline]
+ pub fn bitand(&self, rhs: T) -> LocalRegisterCopy<T, R> {
+ LocalRegisterCopy::new(self.value & rhs)
+ }
+}
+
+impl<T: UIntLike + fmt::Debug, R: RegisterLongName> fmt::Debug for LocalRegisterCopy<T, R> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{:?}", self.value)
+ }
+}
+
+// Helper macro to implement From<LocalRegisterCopy<T: UIntLike>, R>>
+// for <T: UIntLike>
+macro_rules! From_impl_for {
+ ($type:ty) => {
+ impl<R: RegisterLongName> From<LocalRegisterCopy<$type, R>> for $type {
+ fn from(r: LocalRegisterCopy<$type, R>) -> $type {
+ r.value
+ }
+ }
+ };
+}
+
+From_impl_for!(u8);
+From_impl_for!(u16);
+From_impl_for!(u32);
+From_impl_for!(u64);
+From_impl_for!(u128);
+From_impl_for!(usize);
diff --git a/src/macros.rs b/src/macros.rs
new file mode 100644
index 0000000..b8e2c89
--- /dev/null
+++ b/src/macros.rs
@@ -0,0 +1,370 @@
+//! Macros for cleanly defining peripheral registers.
+
+#[macro_export]
+macro_rules! register_fields {
+ // Macro entry point.
+ (@root $(#[$attr_struct:meta])* $vis_struct:vis $name:ident $(<$life:lifetime>)? { $($input:tt)* } ) => {
+ $crate::register_fields!(
+ @munch (
+ $($input)*
+ ) -> {
+ $vis_struct struct $(#[$attr_struct])* $name $(<$life>)?
+ }
+ );
+ };
+
+ // Print the struct once all fields have been munched.
+ (@munch
+ (
+ $(#[$attr_end:meta])*
+ ($offset:expr => @END),
+ )
+ -> {$vis_struct:vis struct $(#[$attr_struct:meta])* $name:ident $(<$life:lifetime>)? $(
+ $(#[$attr:meta])*
+ ($vis:vis $id:ident: $ty:ty)
+ )*}
+ ) => {
+ $(#[$attr_struct])*
+ #[repr(C)]
+ $vis_struct struct $name $(<$life>)? {
+ $(
+ $(#[$attr])*
+ $vis $id: $ty
+ ),*
+ }
+ };
+
+ // Munch field.
+ (@munch
+ (
+ $(#[$attr:meta])*
+ ($offset_start:expr => $vis:vis $field:ident: $ty:ty),
+ $($after:tt)*
+ )
+ -> {$($output:tt)*}
+ ) => {
+ $crate::register_fields!(
+ @munch (
+ $($after)*
+ ) -> {
+ $($output)*
+ $(#[$attr])*
+ ($vis $field: $ty)
+ }
+ );
+ };
+
+ // Munch padding.
+ (@munch
+ (
+ $(#[$attr:meta])*
+ ($offset_start:expr => $padding:ident),
+ $(#[$attr_next:meta])*
+ ($offset_end:expr => $($next:tt)*),
+ $($after:tt)*
+ )
+ -> {$($output:tt)*}
+ ) => {
+ $crate::register_fields!(
+ @munch (
+ $(#[$attr_next])*
+ ($offset_end => $($next)*),
+ $($after)*
+ ) -> {
+ $($output)*
+ $(#[$attr])*
+ ($padding: [u8; $offset_end - $offset_start])
+ }
+ );
+ };
+}
+
+// TODO: All of the rustdoc tests below use a `should_fail` attribute instead of
+// `should_panic` because a const panic will result in a failure to evaluate a
+// constant value, and thus a compiler error. However, this means that these
+// examples could break for unrelated reasons, trigger a compiler error, but not
+// test the desired assertion any longer. This should be switched to a
+// `should_panic`-akin attribute which works for const panics, once that is
+// available.
+/// Statically validate the size and offsets of the fields defined
+/// within the register struct through the `register_structs!()`
+/// macro.
+///
+/// This macro expands to an expression which contains static
+/// assertions about various parameters of the individual fields in
+/// the register struct definition. It will test for:
+///
+/// - Proper start offset of padding fields. It will fail in cases
+/// such as
+///
+/// ```should_fail
+/// # #[macro_use]
+/// # extern crate tock_registers;
+/// # use tock_registers::register_structs;
+/// # use tock_registers::registers::ReadWrite;
+/// register_structs! {
+/// UartRegisters {
+/// (0x04 => _reserved),
+/// (0x08 => foo: ReadWrite<u32>),
+/// (0x0C => @END),
+/// }
+/// }
+/// # // This is required for rustdoc to not place this code snipped into an
+/// # // fn main() {...} function.
+/// # fn main() { }
+/// ```
+///
+/// In this example, the start offset of `_reserved` should have been `0x00`
+/// instead of `0x04`.
+///
+/// - Correct start offset and end offset (start offset of next field) in actual
+/// fields. It will fail in cases such as
+///
+/// ```should_fail
+/// # #[macro_use]
+/// # extern crate tock_registers;
+/// # use tock_registers::register_structs;
+/// # use tock_registers::registers::ReadWrite;
+/// register_structs! {
+/// UartRegisters {
+/// (0x00 => foo: ReadWrite<u32>),
+/// (0x05 => bar: ReadWrite<u32>),
+/// (0x08 => @END),
+/// }
+/// }
+/// # // This is required for rustdoc to not place this code snipped into an
+/// # // fn main() {...} function.
+/// # fn main() { }
+/// ```
+///
+/// In this example, the start offset of `bar` and thus the end offset of
+/// `foo` should have been `0x04` instead of `0x05`.
+///
+/// - Invalid alignment of fields.
+///
+/// - That the end marker matches the actual generated struct size. This will
+/// fail in cases such as
+///
+/// ```should_fail
+/// # #[macro_use]
+/// # extern crate tock_registers;
+/// # use tock_registers::register_structs;
+/// # use tock_registers::registers::ReadWrite;
+/// register_structs! {
+/// UartRegisters {
+/// (0x00 => foo: ReadWrite<u32>),
+/// (0x04 => bar: ReadWrite<u32>),
+/// (0x10 => @END),
+/// }
+/// }
+/// # // This is required for rustdoc to not place this code snipped into an
+/// # // fn main() {...} function.
+/// # fn main() { }
+/// ```
+#[macro_export]
+macro_rules! test_fields {
+ // This macro works by iterating over all defined fields, until it hits an
+ // ($size:expr => @END) field. Each iteration generates an expression which,
+ // when evaluated, yields the current byte offset in the fields. Thus, when
+ // reading a field or padding, the field or padding length must be added to
+ // the returned size.
+ //
+ // By feeding this expression recursively into the macro, deeper invocations
+ // can continue validating fields through knowledge of the current offset
+ // and the remaining fields.
+ //
+ // The nested expression returned by this macro is guaranteed to be
+ // const-evaluable.
+
+ // Macro entry point.
+ (@root $struct:ident $(<$life:lifetime>)? { $($input:tt)* } ) => {
+ // Start recursion at offset 0.
+ $crate::test_fields!(@munch $struct $(<$life>)? ($($input)*) : (0, 0));
+ };
+
+ // Consume the ($size:expr => @END) field, which MUST be the last field in
+ // the register struct.
+ (@munch $struct:ident $(<$life:lifetime>)?
+ (
+ $(#[$attr_end:meta])*
+ ($size:expr => @END),
+ )
+ : $stmts:expr
+ ) => {
+ const _: () = {
+ // We've reached the end! Normally it is sufficient to compare the
+ // struct's size to the reported end offet. However, we must
+ // evaluate the previous iterations' expressions for them to have an
+ // effect anyways, so we can perform an internal sanity check on
+ // this value as well.
+ const SUM_MAX_ALIGN: (usize, usize) = $stmts;
+ const SUM: usize = SUM_MAX_ALIGN.0;
+ const MAX_ALIGN: usize = SUM_MAX_ALIGN.1;
+
+ // Internal sanity check. If we have reached this point and
+ // correctly iterated over the struct's fields, the current offset
+ // and the claimed end offset MUST be equal.
+ assert!(SUM == $size);
+
+ const STRUCT_SIZE: usize = core::mem::size_of::<$struct $(<$life>)?>();
+ const ALIGNMENT_CORRECTED_SIZE: usize = if $size % MAX_ALIGN != 0 { $size + (MAX_ALIGN - ($size % MAX_ALIGN)) } else { $size };
+
+ assert!(
+ STRUCT_SIZE == ALIGNMENT_CORRECTED_SIZE,
+ "{}",
+ concat!(
+ "Invalid size for struct ",
+ stringify!($struct),
+ " (expected ",
+ $size,
+ ", actual struct size differs)",
+ ),
+ );
+ };
+ };
+
+ // Consume a proper ($offset:expr => $field:ident: $ty:ty) field.
+ (@munch $struct:ident $(<$life:lifetime>)?
+ (
+ $(#[$attr:meta])*
+ ($offset_start:expr => $vis:vis $field:ident: $ty:ty),
+ $(#[$attr_next:meta])*
+ ($offset_end:expr => $($next:tt)*),
+ $($after:tt)*
+ )
+ : $output:expr
+ ) => {
+ $crate::test_fields!(
+ @munch $struct $(<$life>)? (
+ $(#[$attr_next])*
+ ($offset_end => $($next)*),
+ $($after)*
+ ) : {
+ // Evaluate the previous iterations' expression to determine the
+ // current offset.
+ const SUM_MAX_ALIGN: (usize, usize) = $output;
+ const SUM: usize = SUM_MAX_ALIGN.0;
+ const MAX_ALIGN: usize = SUM_MAX_ALIGN.1;
+
+ // Validate the start offset of the current field. This check is
+ // mostly relevant for when this is the first field in the
+ // struct, as any subsequent start offset error will be detected
+ // by an end offset error of the previous field.
+ assert!(
+ SUM == $offset_start,
+ "{}",
+ concat!(
+ "Invalid start offset for field ",
+ stringify!($field),
+ " (expected ",
+ $offset_start,
+ " but actual value differs)",
+ ),
+ );
+
+ // Validate that the start offset of the current field within
+ // the struct matches the type's minimum alignment constraint.
+ const ALIGN: usize = core::mem::align_of::<$ty>();
+ // Clippy can tell that (align - 1) is zero for some fields, so
+ // we allow this lint and further encapsule the assert! as an
+ // expression, such that the allow attr can apply.
+ #[allow(clippy::bad_bit_mask)]
+ {
+ assert!(
+ SUM & (ALIGN - 1) == 0,
+ "{}",
+ concat!(
+ "Invalid alignment for field ",
+ stringify!($field),
+ " (offset differs from expected)",
+ ),
+ );
+ }
+
+ // Add the current field's length to the offset and validate the
+ // end offset of the field based on the next field's claimed
+ // start offset.
+ const NEW_SUM: usize = SUM + core::mem::size_of::<$ty>();
+ assert!(
+ NEW_SUM == $offset_end,
+ "{}",
+ concat!(
+ "Invalid end offset for field ",
+ stringify!($field),
+ " (expected ",
+ $offset_end,
+ " but actual value differs)",
+ ),
+ );
+
+ // Determine the new maximum alignment. core::cmp::max(ALIGN,
+ // MAX_ALIGN) does not work here, as the function is not const.
+ const NEW_MAX_ALIGN: usize = if ALIGN > MAX_ALIGN { ALIGN } else { MAX_ALIGN };
+
+ // Provide the updated offset and alignment to the next
+ // iteration.
+ (NEW_SUM, NEW_MAX_ALIGN)
+ }
+ );
+ };
+
+ // Consume a padding ($offset:expr => $padding:ident) field.
+ (@munch $struct:ident $(<$life:lifetime>)?
+ (
+ $(#[$attr:meta])*
+ ($offset_start:expr => $padding:ident),
+ $(#[$attr_next:meta])*
+ ($offset_end:expr => $($next:tt)*),
+ $($after:tt)*
+ )
+ : $output:expr
+ ) => {
+ $crate::test_fields!(
+ @munch $struct $(<$life>)? (
+ $(#[$attr_next])*
+ ($offset_end => $($next)*),
+ $($after)*
+ ) : {
+ // Evaluate the previous iterations' expression to determine the
+ // current offset.
+ const SUM_MAX_ALIGN: (usize, usize) = $output;
+ const SUM: usize = SUM_MAX_ALIGN.0;
+ const MAX_ALIGN: usize = SUM_MAX_ALIGN.1;
+
+ // Validate the start offset of the current padding field. This
+ // check is mostly relevant for when this is the first field in
+ // the struct, as any subsequent start offset error will be
+ // detected by an end offset error of the previous field.
+ assert!(
+ SUM == $offset_start,
+ concat!(
+ "Invalid start offset for padding ",
+ stringify!($padding),
+ " (expected ",
+ $offset_start,
+ " but actual value differs)",
+ ),
+ );
+
+ // The padding field is automatically sized. Provide the start
+ // offset of the next field to the next iteration.
+ ($offset_end, MAX_ALIGN)
+ }
+ );
+ };
+}
+
+#[macro_export]
+macro_rules! register_structs {
+ {
+ $(
+ $(#[$attr:meta])*
+ $vis_struct:vis $name:ident $(<$life:lifetime>)? {
+ $( $fields:tt )*
+ }
+ ),*
+ } => {
+ $( $crate::register_fields!(@root $(#[$attr])* $vis_struct $name $(<$life>)? { $($fields)* } ); )*
+ $( $crate::test_fields!(@root $name $(<$life>)? { $($fields)* } ); )*
+ };
+}
diff --git a/src/registers.rs b/src/registers.rs
new file mode 100644
index 0000000..c11a979
--- /dev/null
+++ b/src/registers.rs
@@ -0,0 +1,181 @@
+//! Implementation of included register types.
+//!
+//! This module provides a standard set of register types, which can
+//! describe different access levels:
+//!
+//! - [`ReadWrite`] for registers which can be read and written to
+//! - [`ReadOnly`] for registers which can only be read
+//! - [`WriteOnly`] for registers which can only be written to
+//! - [`Aliased`] for registers which can be both read and written,
+//! but represent different registers depending on the operation
+//! - [`InMemoryRegister`] provide a register-type in RAM using
+//! volatile operations
+//!
+//! These types can be disabled by removing the `register_types` crate
+//! feature (part of the default features). This is useful if this
+//! crate should be used only as an interface library, or if all
+//! unsafe code should be disabled.
+
+use core::cell::UnsafeCell;
+use core::marker::PhantomData;
+
+use crate::interfaces::{Readable, Writeable};
+use crate::{RegisterLongName, UIntLike};
+
+/// Read/Write registers.
+///
+/// For accessing and manipulating the register contents, the
+/// [`Readable`], [`Writeable`] and
+/// [`ReadWriteable`](crate::interfaces::ReadWriteable) traits are
+/// implemented.
+// To successfully alias this structure onto hardware registers in memory, this
+// struct must be exactly the size of the `T`.
+#[repr(transparent)]
+pub struct ReadWrite<T: UIntLike, R: RegisterLongName = ()> {
+ value: UnsafeCell<T>,
+ associated_register: PhantomData<R>,
+}
+impl<T: UIntLike, R: RegisterLongName> Readable for ReadWrite<T, R> {
+ type T = T;
+ type R = R;
+
+ #[inline]
+ fn get(&self) -> Self::T {
+ unsafe { ::core::ptr::read_volatile(self.value.get()) }
+ }
+}
+impl<T: UIntLike, R: RegisterLongName> Writeable for ReadWrite<T, R> {
+ type T = T;
+ type R = R;
+
+ #[inline]
+ fn set(&self, value: T) {
+ unsafe { ::core::ptr::write_volatile(self.value.get(), value) }
+ }
+}
+
+/// Read-only registers.
+///
+/// For accessing the register contents the [`Readable`] trait is
+/// implemented.
+// To successfully alias this structure onto hardware registers in memory, this
+// struct must be exactly the size of the `T`.
+#[repr(transparent)]
+pub struct ReadOnly<T: UIntLike, R: RegisterLongName = ()> {
+ value: T,
+ associated_register: PhantomData<R>,
+}
+impl<T: UIntLike, R: RegisterLongName> Readable for ReadOnly<T, R> {
+ type T = T;
+ type R = R;
+
+ #[inline]
+ fn get(&self) -> T {
+ unsafe { ::core::ptr::read_volatile(&self.value) }
+ }
+}
+
+/// Write-only registers.
+///
+/// For setting the register contents the [`Writeable`] trait is
+/// implemented.
+// To successfully alias this structure onto hardware registers in memory, this
+// struct must be exactly the size of the `T`.
+#[repr(transparent)]
+pub struct WriteOnly<T: UIntLike, R: RegisterLongName = ()> {
+ value: UnsafeCell<T>,
+ associated_register: PhantomData<R>,
+}
+impl<T: UIntLike, R: RegisterLongName> Writeable for WriteOnly<T, R> {
+ type T = T;
+ type R = R;
+
+ #[inline]
+ fn set(&self, value: T) {
+ unsafe { ::core::ptr::write_volatile(self.value.get(), value) }
+ }
+}
+
+/// Read-only and write-only registers aliased to the same address.
+///
+/// Unlike the [`ReadWrite`] register, this represents a register
+/// which has different meanings based on if it is written or read.
+/// This might be found on a device where control and status registers
+/// are accessed via the same memory address via writes and reads,
+/// respectively.
+///
+/// This register implements [`Readable`] and [`Writeable`], but in
+/// general does not implement
+/// [`ReadWriteable`](crate::interfaces::ReadWriteable) (only if the
+/// type parameters `R` and `W` are identical, in which case a
+/// [`ReadWrite`] register might be a better choice).
+// To successfully alias this structure onto hardware registers in memory, this
+// struct must be exactly the size of the `T`.
+#[repr(transparent)]
+pub struct Aliased<T: UIntLike, R: RegisterLongName = (), W: RegisterLongName = ()> {
+ value: UnsafeCell<T>,
+ associated_register: PhantomData<(R, W)>,
+}
+impl<T: UIntLike, R: RegisterLongName, W: RegisterLongName> Readable for Aliased<T, R, W> {
+ type T = T;
+ type R = R;
+
+ #[inline]
+ fn get(&self) -> Self::T {
+ unsafe { ::core::ptr::read_volatile(self.value.get()) }
+ }
+}
+impl<T: UIntLike, R: RegisterLongName, W: RegisterLongName> Writeable for Aliased<T, R, W> {
+ type T = T;
+ type R = W;
+
+ #[inline]
+ fn set(&self, value: Self::T) {
+ unsafe { ::core::ptr::write_volatile(self.value.get(), value) }
+ }
+}
+
+/// In memory volatile register.
+///
+/// Like [`ReadWrite`], but can be safely constructed using the
+/// [`InMemoryRegister::new`] method. It will always be initialized to
+/// the passed in, well-defined initial value.
+///
+/// For accessing and manipulating the register contents, the
+/// [`Readable`], [`Writeable`] and
+/// [`ReadWriteable`](crate::interfaces::ReadWriteable) traits are
+/// implemented.
+// To successfully alias this structure onto hardware registers in memory, this
+// struct must be exactly the size of the `T`.
+#[repr(transparent)]
+pub struct InMemoryRegister<T: UIntLike, R: RegisterLongName = ()> {
+ value: UnsafeCell<T>,
+ associated_register: PhantomData<R>,
+}
+
+impl<T: UIntLike, R: RegisterLongName> InMemoryRegister<T, R> {
+ pub const fn new(value: T) -> Self {
+ InMemoryRegister {
+ value: UnsafeCell::new(value),
+ associated_register: PhantomData,
+ }
+ }
+}
+impl<T: UIntLike, R: RegisterLongName> Readable for InMemoryRegister<T, R> {
+ type T = T;
+ type R = R;
+
+ #[inline]
+ fn get(&self) -> Self::T {
+ unsafe { ::core::ptr::read_volatile(self.value.get()) }
+ }
+}
+impl<T: UIntLike, R: RegisterLongName> Writeable for InMemoryRegister<T, R> {
+ type T = T;
+ type R = R;
+
+ #[inline]
+ fn set(&self, value: T) {
+ unsafe { ::core::ptr::write_volatile(self.value.get(), value) }
+ }
+}