New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Unify arithmetic implementation of field registers and add unit tests. #1766
Conversation
This is a good observation, and arguably the implementation of
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me, but I'm not really a steward of this code, so my approval shouldn't weigh too heavily.
@andre-richter if you've got the time, it would be good to get your thoughts on this as someone using the registers interface externally. |
I won’t have time to adapt to breaking changes Immediately , but that’s also not an issue since we have the previous versions on crates.io until I can adapt. I guess a bump to 6.0.0 makes sense for this due to the breakage. |
As of now, the changes should not be breaking - the API is simply extended with more functions for So I think we can merge the current changes as a 5.x update, and then in a separate PR explore the traits I proposed for a 6.x version. |
Also, @andre-richter can you confirm that the following unit-test gating works for you? #[cfg(not(feature = "no_std_unit_tests"))]
#[cfg(test)] |
@gendx, misread the breaking part, sorry. I pulled your patch locally and pointed a local register-rs crate copy to it, which I then hooked into a build of one of my kernels at https://github.com/rust-embedded/rust-raspberrypi-OS-tutorials/tree/master/14_exceptions_part2_peripheral_IRQs Everything compiled and booted, and the unit-test gate also worked. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good; I'd say it can be merged right after the Tock 1.5 release.
For the new traits, if I understand correctly, they remove code duplication in this library, at the expense of slightly more verbose code (extra imports) in the users of the library. I'm not sure that's the right tradeoff to make?
It's a bit unfortunate that traits have to be manually imported for their functions to be available in Rust. The idiomatic way for crates to solve this problem is to provide some kind of However, Tock has a hard ban on wildcard imports (despite no such support in a Rust compiler flag). IMO the verbosity trade-off is more caused by this choice than by some specific traits. If we choose to reject any wildcard imports, then in exchange we accept more verbosity in imports. |
Yeah, maybe this is the "I'm a luddite with no IDE speaking" [or as a person who reviews code in a browser, or via email, or any of the numerous places where tooling can't solve this problem], but the that's a terrible idiom :). Wildcard imports generally break the idea of "I'm reading this code and there's this magic thing, where did it come from?" Not anywhere else in this file? Oh, let me go search the pile of Style aside, I guess the question is whether we get any material benefit from the new traits for users of the library? I think that interface is much more important, and imposing small costs on the implementation of a library to make its usage easier / cleaner is generally a worthwhile tradeoff. |
I don't have a strong opinion on the Regarding the benefits of an implementation for their users, I don't think they are limited to the API surface. A simpler implementation is also more robust to refactoring, easier to unit test, etc. So the benefits to the users of such a library is a better tested, more robust, more reliable code with fewer bugs. Especially in the long-term of the software engineering life-cycle (less likely that someone adding code in 6 months introduces or fixes a bug or performance regression/improvement for only one of the register types). If the "cost" is more traits to imports, I think it's totally reasonable. And if that's too high of a cost we can also reconsider the wildcard imports and/or add some weight in the balance for rust-lang/cargo#6278 to be fixed. |
Yeah, I guess if the "cost" is just trait imports, that's pretty minimal overhead. I'd be more reticent if it required changes at use sites, but I don't think that would be the case here. |
The functions would be the same. Just moved to traits instead of being duplicated in each of the types. |
Okay, I think status is this PR is pending 1.5 release, then ready to merge. Then a subsequent PR for the trait updates makes sense. |
bors r+ |
This PR was included in a batch that successfully built, but then failed to merge into master (it was a non-fast-forward update). It will be automatically retried. |
1939: Make the Field::mask and FieldValue::mask fields private. r=alistair23 a=gendx ### Pull Request Overview The `mask` fields don't need to be exposed publicly, as their use cases overlap with the existing functions to manipulate fields. - This pull request makes them private. - As a side effect, the `libraries/riscv-csr/src/csr.rs` is refactored to use the unified arithmetic methods introduced in #1766. ### Testing Strategy This pull request was tested by CI. ### TODO or Help Wanted - These changes currently overlap with #1926, although are compatible with that PR, as discussed in #1926 (comment). - The `Field::shift` field should also be made private, but is currently used in `chips/lowrisc/src/gpio.rs`. That code should probably be refactored so that the shift is not exposed as-is. https://github.com/tock/tock/blob/555b3a0441697d111a0330c01d392c15b36712f6/chips/lowrisc/src/gpio.rs#L94-L104 - Likewise, the `FieldValue::value` field should be made private, but is currently used in https://github.com/tock/tock/blob/555b3a0441697d111a0330c01d392c15b36712f6/libraries/riscv-csr/src/csr.rs#L76-L79 ### Documentation Updated - [x] Updated the relevant files in `/docs`, or no updates are required. ### Formatting - [x] Ran `make prepush`. Co-authored-by: Guillaume Endignoux <guillaumee@google.com>
Pull Request Overview
While reviewing #1661 (comment), it came up that there is some amount of code duplication in the arithmetic operations on various register types.
This pull request unifies the implementation, by adding new functions to the
Field
andFieldValue
types, and making the other types use these. Unit tests are also added for these unified functions.Some formulas are also simplified:
(value << shift) & (mask << shift)
=>(value & mask) << shift
(val & (field.mask << field.shift)) >> field.shift != T::zero()
=>val & (field.mask << field.shift) != T::zero()
Testing Strategy
This pull request was tested by Travis-CI.
TODO or Help Wanted
matches_any(&self, field: FieldValue<T, R>) -> bool
doesn't makes a lot of sense to me, because it doesn't use any "value" of the field. It could bematches_any(&self, field: Field<T, R>) -> bool
instead. But then it's the same as the existingis_set(&self, field: Field<T, R>) -> bool
. Shouldmatches_any
be removed? Tock doesn't use a lot ofmatches_any
.ReadWrite
andInMemoryRegister
have the same implementation. Is that intended? I wonder why volatile read/write are needed forInMemoryRegister
- given that such "register" is not MMIO. Tock doesn't use a lot ofInMemoryRegister
.Here is a draft of that:
Documentation Updated
/docs
, or no updates are required.Formatting
make formatall
.