-
-
Notifications
You must be signed in to change notification settings - Fork 771
tock-registers: added debug()
method in registers for better human readable debug output
#3771
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
Conversation
So, the idea is to get an easy view of the data inside, especially for more complex fields. Currently it does the following: - It will try to parse the enum if it can, otherwise it will just print the value as a number (not hex). - If the value is not enum (wasn't created with [<fields>]), it will just print the number. - Unless its 1 bit, it will print it as a bool. This change is completely hidden from the API, and shouldn't change anything, the feature is not enabled by default. When the feature is disabled, the resulting code is exactly the same before this commit.
Can you include an example output? Also, the relevant doc is probably just the readme for the crate. |
Example: I'm using the example shown in the crate itself tock_registers::register_bitfields! [u32,
Control [
RANGE OFFSET(4) NUMBITS(2) [
VeryHigh = 0,
High = 1,
Low = 2
],
EN OFFSET(3) NUMBITS(1) [],
INT OFFSET(2) NUMBITS(1) []
],
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) []
],
InterruptFlags [
UNDES 10,
TXEMPTY 9,
NSSR 8,
OVRES 3,
MODF 2,
TDRE 1,
RDRF 0
]
];
fn main() {
let control = LocalRegisterCopy::<u32, Control::Register>::new(0x0);
let status = LocalRegisterCopy::<u32, Status::Register>::new(0x0);
let flags = LocalRegisterCopy::<u32, InterruptFlags::Register>::new(0xFF);
println!("control = {:?}", control);
println!("status = {:?}", status);
println!("flags = {:?}", flags);
} With the feature
Here we are using boolean for 1 bit fields, enums are printed correctly, and if the value is not 1 bit and not enum it is printed as a number Without this feature it will just output normal
I put this specifically in |
Thank you for this contribution. In general, we're somewhat hesitant to add compilation features to crates in the Tock ecosystem -- they are not easily testable in CI (in particular, all permutations of features), and also not fine grained. Given that many crates rely on the Another way to selectively add such more verbose debugging output could be a wrapper type, such as (with the trait named trait RegisterDebugInfo {
// methods to query the required debug information
fn debug<'a>(&'a self) -> RegisterDebug<'a, Self> {
RegisterDebug(self)
}
}
pub struct RegisterDebug<'a, R: RegisterDebugInfo>(&'a R);
impl<'a, R: RegisterDebugInfo> fmt::Debug for RegisterDebug<'a, R> { ... } This would allow us to avoid conditional compilation, while not generating any additional code if this infrastructure is not used. Another improvement could be to avoid the use of macros to both parse and format our custom |
Thanks @lschuermann , these are really nice ideas for optimization and reducing code. I'll work on it. |
Use very minimal info from the macro generating the fields, and instead use the types system to opt into Debug. This allows more flexible usage and also doesn't affect old implementation
Made it much simpler, now we just call `debug` and we pass the `DebugInfo` of the register. This way we need to be explicit when passing the argument. Not sure if its better this way?
Fixed compilation when we don't specify the flag. TODO: we still need to modify the documentation.
Removed depndancy on `RegisterLongName`. Added a new struct `DebugInfo` instead of a type, this will hold register debug information
We don't implement `DebugField` for `(Field,)` which is a valid tuple. We don't need to do that, just fix how we create the tuple
This was removed by mistake while implemting `debug` for `LocalRegisterCopy`
Support up to 64 fields I would really like to change this to something better somehow.
Hello @lschuermann , I have implemented a new way to use It's called with There are some stuff we can discuss.
Let me know what you think. Thanks |
Build docs for this feature as well
We don't need to implement for infinite numbers ourselves, since this is auto generated by macro, users won't need to write this structure Since thats the case, we can do recursion. For my testing on `tock` this didn't result in invocation overflow which is good
…s only This is better in the sense that we can return an array of fields directly.
This reverts commit 69b6f25.
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 is great, the type & trait structure works out exactly as I have imagined and the implementation is very clean. I'm still a little concerned about the macro duplication we have going on here, so merging the impl_register_debug!
with the register_bitfields!
macros would be great.
…ebug` module by default Now the `debug` traits and structs will be available by default, but the `debug` function won't be, so it should be all optimized away
I'm thinking of removing the |
I think that's a good idea. If those functions are not used, they shouldn't have any runtime overheads (flash or RAM). One exception has historically been when you convert such a type into a trait object, which will generate a vtable that then holds references to these methods. If this is still an issue it needs to be solved upstream with the Rust compiler, and we can work around it by simply avoiding conversions into trait objects. I was also thinking about removing the feature-flag entirely. As long as we actively have to call |
…bug` This is much simpler to user, then the rest is handled by the Rust compiler for optimization. From `lschuermann`: One exception has historically been when you convert such a type into a trait object, which will generate a vtable that then holds references to these methods. If this is still an issue it needs to be solved upstream with the Rust compiler, and we can work around it by simply avoiding conversions into trait objects.
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 fine to me, but I'm not really a maintainer of the registers library.
0a59bf2
to
61f5338
Compare
@Amjad50 I spent some good amount of time to look through all the code, and this is pretty awesome. The idea to build a sequence of types in the macro and then recurse through them, taking two mutable closures with you, is very clever. It took me quite some time to really understand why all of this works. In hopes to improve on that a bit, I took the liberty to push a commit to this PR:
Let me know whether these changes look good to you. |
This commit refactors the newly introduced RegisterDebugInfo / RegisterDebugValue infrastructure: - It improves documentation. In particular, it attempts to clearly communicate guarantees offered by the various APIs introduced, such as in the `FieldValueEnumSeq` (né `EnumDebug`) or `RegisterDebugInfo` trait. It fixes a minor issue where the `Debuggable` trait description in the `interfaces` module documentation was misplaced. - It introduces a proper field value enum type sequence trait (`FieldValueEnumSeq`), which has a cons `FieldValueEnumCons` and nil `FieldValueEnumNil` constructor. While tuples offer a more compact way to represent the same, they are incredibly hard to read with many levels of nesting, and don't offer type uniqueness. Also, this new type sequence uses _cons_ and _nil_ constructors, versus a _cons_ / _last_ style sequence. This happens to be closer to constructs found in other functional languages and avoid special-casing the empty-sequence case. - Adds a small test + demo of the `.debug()` method to the `fields` module doc-comment.
61f5338
to
ee30688
Compare
Thanks @lschuermann, these are really nice additions and improvements. Beside the above small comment, I think the new changes are very good. |
…ter_bitfields! macro
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.
Thanks for looking over my commit. I think this is a pretty cool and solid addition. Also, the size-check benchmarks confirm that this doesn't have any impact on flash size: https://github.com/tock/tock/actions/runs/7557181806/job/20654379855 (the small differences can be explain with a diverging base branch).
I feel sorry for making it hard to understand.
Oh, no worries -- it wasn't particularly hard to understand. Sometimes it just helps to have a second set of eyes look over it, in particular for changes that include a lot of macro-rules magic.
Can you perhaps update the PR title to reflect that this no longer requires the feature? I think then this is good to go.
debug_registers
feat to generate better Debug
debug()
method in registers for better human readable debug output
Updated! |
Seems to have been a fluke with GitHub's Mac runner. |
Pull Request Overview
So, the idea is to get an easy view of the data inside, especially for more complex fields.
Currently it does the following:
This change is completely hidden from the API, and shouldn't change anything, the feature is not enabled by default.
When the feature is disabled, the resulting code is exactly the same before this commit.
Testing Strategy
I didn't add tests, since its not that simple as we would need to use
String
to performfmt::Debug
in memory.But if its needed, please let me know.
TODO or Help Wanted
All good as per the use case I was thinking of, but we can discuss more on the features that we can add and the behavior of the debug for various types of field. Like, with 1 bit, should we print as
bool
or just keep it a number.Documentation Updated
I don't see
tock_registers
mentioned in/docs
so not sure if we should add some docs for this change./docs
, or no updates are required.Formatting
make prepush
.