-
Notifications
You must be signed in to change notification settings - Fork 653
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
cortex-m: Add initial dwt and dcb support #3246
Conversation
The DWT and DCB peripherals are used to access various debug functionality in the chip, such as various counters. This commits adds register descriptions for most of DWT and some of DCB. It also adds a very simple capsule that allows reading the cycle counter from userspace.
arch/cortex-m/src/dwt.rs
Outdated
const DWT: StaticRef<DwtRegisters> = unsafe { StaticRef::new(0xE0001000 as *const DwtRegisters) }; | ||
|
||
/// Enable the cycle counter | ||
/// [`DCB::enable_debug_and_trace()`] needs to be enabled for this to work |
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.
Why not just do that then?
@@ -8,3 +8,4 @@ edition = "2021" | |||
kernel = { path = "../kernel" } | |||
enum_primitive = { path = "../libraries/enum_primitive" } | |||
tickv = { path = "../libraries/tickv" } | |||
cortexm = { path = "../arch/cortex-m" } |
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.
We cannot make capsules dependent on something chip specific.
Instead, we have to use a HIL to abstract HW from capsules.
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.
Ok, I'll take a look and amend the pr
use kernel::utilities::registers::{register_bitfields, register_structs, ReadWrite}; | ||
use kernel::utilities::StaticRef; | ||
|
||
//TODO: Rest of the Registers |
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.
arch/cortex-m/src/dcb.rs
Outdated
register_bitfields![u32, | ||
DebugExceptionAndMonitorControl [ | ||
/// Write 1 to globally enable all DWT and ITM features. | ||
/// RW. |
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 whole register is declared ReadWrite
already; are the RO/WO
fields? If not, these RW
s should probably be removed.
arch/cortex-m/src/dcb.rs
Outdated
/// Enable the Debug and Trace unit `DWT` | ||
/// This has to be enabled before using any feature of the `DWT` | ||
pub fn enable_debug_and_trace() { | ||
DCB.demcr | ||
.modify(DebugExceptionAndMonitorControl::TRCENA::SET); | ||
} | ||
|
||
/// Disable the Debug and Trace unit `DWT` | ||
pub unsafe fn disable_debug_and_trace() { | ||
DCB.demcr | ||
.modify(DebugExceptionAndMonitorControl::TRCENA::CLEAR); |
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.
Consider wrapping DWT in a PeripheralManager
instance (e.g.
Line 569 in 7fcb766
impl PeripheralManagement<TWIMClock> for I2CHw { |
/// Interface for interacting with debug hardware integrated in various SoCs. | ||
/// Currently allows reading the cycle counter and can be expanded to allow | ||
/// access to other features in the future. |
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.
/// Interface for interacting with debug hardware integrated in various SoCs. | |
/// Currently allows reading the cycle counter and can be expanded to allow | |
/// access to other features in the future. | |
//! Interface for interacting with debug hardware integrated in various SoCs. | |
//! | |
//! Currently allows reading the cycle counter. |
use crate::ErrorCode; | ||
|
||
pub trait PerformanceCounters { | ||
/// Enable the cycle counter. Returns an error, if the cycle counter is not present. |
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.
Which error?
/// access to other features in the future. | ||
use crate::ErrorCode; | ||
|
||
pub trait PerformanceCounters { |
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.
pub trait PerformanceCounters { | |
pub trait CycleCounter { |
?
@@ -0,0 +1,15 @@ | |||
/// Interface for interacting with debug hardware integrated in various SoCs. |
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.
"debug.rs" is somewhat generic, and there is the potential for confusion with kernel/src/debug.rs
. Is there a name that would be somewhat more informative? Maybe hw_debug
?
@@ -0,0 +1,51 @@ | |||
//! Provides a performance counter interface for userspace. |
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.
perf.rs
is too short. If this is for cycle counts, let's name it that.
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.
I would love to see DWT support merged, I end up using some modified version of what Amit wrote for the PowerClocks paper all the time when taking performance measurements, and its always a pain to have to throw it somewhere in the kernel.
While I don't think this PR has to be updated to include this, I do think it would be really nice to see this functionality added to kernel/src/debug.rs
(similar to debug!()
and debug_gpio!()
) so that it is easy to take performance measurements from anywhere. This would require some sort of global that boards would initialize with the appropriate implementation of the HIL, or perhaps we could configure it using KernelResources
/* | ||
// TODO: register_bitfields | ||
// Peripheral Identification Register 4 | ||
(0xFD0 => pid4: ReadOnly<u32, Pid4::Register>), | ||
|
||
// Peripheral Identification Register 5 | ||
(0xFD4 => pid5: ReadOnly<u32, Pid5::Register>), | ||
|
||
// Peripheral Identification Register 6 | ||
(0xFD8 => pid6: ReadOnly<u32, Pid6::Register>), | ||
|
||
// Peripheral Identification Register 7 | ||
(0xFDC => pid7: ReadOnly<u32, Pid7::Register>), | ||
|
||
// Peripheral Identification Register 0 | ||
(0xFE0 => pid0: ReadOnly<u32, Pid0::Register>), | ||
|
||
// Peripheral Identification Register 1 | ||
(0xFE4 => pid1: ReadOnly<u32, Pid1::Register>), | ||
|
||
// Peripheral Identification Register 2 | ||
(0xFE8 => pid2: ReadOnly<u32, Pid2::Register>), | ||
|
||
// Peripheral Identification Register 3 | ||
(0xFEC => pid3: ReadOnly<u32, Pid3::Register>), | ||
|
||
// Component Identification Register 0 | ||
(0xFF0 => cid0: ReadOnly<u32, Cid0::Register>), | ||
|
||
// Component Identification Register 1 | ||
(0xFF4 => cid1: ReadOnly<u32, Cid1::Register>), | ||
|
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.
Lets just delete the unused peripheral identification registers unless you anticipate needing those for something in the short term.
} | ||
|
||
impl hil::debug::PerformanceCounters for Dwt { | ||
fn enable_cycle_counter() -> Result<(), ErrorCode> { |
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.
Personally I would call this start_cycle_counter()
since it actually starts it counting up, rather than just enabling the functionality. Same for disable_cycle_counter()
-- I would just call that stop_cycle_counter()
, and not have it disable the DCB.
} | ||
} | ||
|
||
impl hil::debug::PerformanceCounters for Dwt { |
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.
I think it would also be helpful to add a reset_cycle_counter()
method to this HIL to reset the counter to 0. This saves from having to get the current count and then perform subtraction, and it just an easy interface (imo). Amit wrote a rough DWT implementation a few years ago that I often use when benchmarking, and it just does the following:
pub fn reset_timer() {
DEMCR.set(DEMCR.get() | 0x01000000);
DWT.cycnt.set(0); // reset the counter
DWT.ctrl.set(0); // disable counter;
}
Keeping in mind that on something like the nrf52 this counter will overflow in 67 seconds, it can actually be pretty helpful to be able to reset to 0 rather than have to consider the (somewhat high) possibility of overflow.
Err(ErrorCode::NOSUPPORT) | ||
} | ||
} | ||
|
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.
One other useful function from Amit's old DWT implementation was bench()
which could be used to easily benchmark in-kernel code:
pub unsafe fn bench<F: FnOnce()>(f: F) -> u32 {
reset_timer();
start_timer();
f();
stop_timer();
get_time()
}
I think it would be nice to see something like this included here.
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.
@codingHahn will you have a chance to revisit this? If not, I will try to find time to update this with the various suggestions
Yeah, sorry. I finished my bachelors thesis and had to settle in to working a full time job. I'd love to apply all your suggestions. Problem is that I don't have the board anymore because it belonged to my employer. |
Replaced by #3934 |
Pull Request Overview
The DWT and DCB peripherals are used to access various debug functionality in the chip, such as various counters.
This commit adds register descriptions for most of the DWT and some of the DCB. It also adds a very simple capsule that allows reading the cycle counter from userspace.
Testing Strategy
This pull request was tested by getting the cycle count and it checks out.
TODO or Help Wanted
This pull request still needs the rest of the registers of some peripherals.
The capsule needs to be added to every supported board and could be expanded to grant access to the other capabilities of the peripherals. We also need to consider security implications for allowing debug peripherals in userspace.
Documentation Updated
/docs
, or no updates are required.Formatting
make prepush
.