Skip to content

Commit 3135b88

Browse files
committed
Differentiate comparator 0 as the only one capable of cycle compare
Statically enforces that only comparator 0 on `armv7m` can be configured for cycle comparison by introducing a marker trait differentiating comparator 0 and the rest of them, and only implementing the ability for this configuration on comparator 0. Closes #376
1 parent bef6ed1 commit 3135b88

File tree

2 files changed

+122
-62
lines changed

2 files changed

+122
-62
lines changed

src/peripheral/dwt.rs

+107-56
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,13 @@ pub struct RegisterBlock {
3737
pub pcsr: RO<u32>,
3838
/// Comparators
3939
#[cfg(armv6m)]
40-
pub c: [Comparator; 2],
40+
pub comp: [Comparator<NoCycleCompare>; 2],
41+
#[cfg(not(armv6m))]
42+
/// Cycle count compare enabled Comparator
43+
pub comp0: Comparator<HasCycleCompare>,
4144
#[cfg(not(armv6m))]
4245
/// Comparators
43-
pub c: [Comparator; 16],
46+
pub comp: [Comparator<NoCycleCompare>; 15],
4447
#[cfg(not(armv6m))]
4548
reserved: [u32; 932],
4649
/// Lock Access
@@ -66,16 +69,39 @@ bitfield! {
6669
u8, numcomp, _: 31, 28;
6770
}
6871

72+
mod private {
73+
/// A public trait inaccessible by external users to ensure no one else can
74+
/// impl a sealed trait outside of the crate of origin. For more info on this
75+
/// design pattern, see https://rust-lang.github.io/api-guidelines/future-proofing.html
76+
pub trait Sealed {}
77+
}
78+
79+
/// A zero-sized marker trait indicating the capabilities of a given comparator.
80+
pub trait ComparatorSupportedFunctions: private::Sealed {}
81+
82+
/// Marker indicating that this comparator has cycle comparison abilities. This
83+
/// is the case only for the first comparator for armv7m.
84+
pub enum HasCycleCompare {}
85+
impl ComparatorSupportedFunctions for HasCycleCompare {}
86+
impl private::Sealed for HasCycleCompare {}
87+
88+
/// Marker indicating this comparator does not have cycle comparison abilities. This
89+
/// is the case for all armv6m comparators and comparators 1-15 for armv7m.
90+
pub enum NoCycleCompare {}
91+
impl ComparatorSupportedFunctions for NoCycleCompare {}
92+
impl private::Sealed for NoCycleCompare {}
93+
6994
/// Comparator
7095
#[repr(C)]
71-
pub struct Comparator {
96+
pub struct Comparator<SupportedFunctions: ComparatorSupportedFunctions> {
7297
/// Comparator
7398
pub comp: RW<u32>,
7499
/// Comparator Mask
75100
pub mask: RW<u32>,
76101
/// Comparator Function
77102
pub function: RW<Function>,
78103
reserved: u32,
104+
_supported_functions: core::marker::PhantomData<SupportedFunctions>,
79105
}
80106

81107
bitfield! {
@@ -402,63 +428,88 @@ pub enum ComparatorFunction {
402428
pub enum DwtError {
403429
/// Invalid combination of [AccessType] and [EmitOption].
404430
InvalidFunction,
431+
/// An unsupported function was requested, such as [`CycleCount`](ComparatorFunction::CycleCount) on
432+
/// `armv6m`, or on a comparator other than 0 on `armv7m`.
433+
UnsupportedFunction,
405434
}
406435

407-
impl Comparator {
408-
/// Configure the function of the comparator
436+
impl<SupportedFunctions: ComparatorSupportedFunctions> Comparator<SupportedFunctions> {
437+
/// Private function for configuring address compare on any [`Comparator`] since they all support this.
438+
/// Utilized publicly through [`Comparator::configure`]
439+
fn configure_address_compare(
440+
&self,
441+
settings: ComparatorAddressSettings,
442+
) -> Result<(), DwtError> {
443+
// FUNCTION, EMITRANGE
444+
// See Table C1-14
445+
let (function, emit_range) = match (&settings.access_type, &settings.emit) {
446+
(AccessType::ReadOnly, EmitOption::Data) => (0b1100, false),
447+
(AccessType::ReadOnly, EmitOption::Address) => (0b1100, true),
448+
(AccessType::ReadOnly, EmitOption::AddressData) => (0b1110, true),
449+
(AccessType::ReadOnly, EmitOption::PCData) => (0b1110, false),
450+
(AccessType::ReadOnly, EmitOption::WatchpointDebugEvent) => (0b0101, false),
451+
(AccessType::ReadOnly, EmitOption::CompareMatchEvent) => (0b1001, false),
452+
453+
(AccessType::WriteOnly, EmitOption::Data) => (0b1101, false),
454+
(AccessType::WriteOnly, EmitOption::Address) => (0b1101, true),
455+
(AccessType::WriteOnly, EmitOption::AddressData) => (0b1111, true),
456+
(AccessType::WriteOnly, EmitOption::PCData) => (0b1111, false),
457+
(AccessType::WriteOnly, EmitOption::WatchpointDebugEvent) => (0b0110, false),
458+
(AccessType::WriteOnly, EmitOption::CompareMatchEvent) => (0b1010, false),
459+
460+
(AccessType::ReadWrite, EmitOption::Data) => (0b0010, false),
461+
(AccessType::ReadWrite, EmitOption::Address) => (0b0001, true),
462+
(AccessType::ReadWrite, EmitOption::AddressData) => (0b0010, true),
463+
(AccessType::ReadWrite, EmitOption::PCData) => (0b0011, false),
464+
(AccessType::ReadWrite, EmitOption::WatchpointDebugEvent) => (0b0111, false),
465+
(AccessType::ReadWrite, EmitOption::CompareMatchEvent) => (0b1011, false),
466+
467+
(AccessType::ReadWrite, EmitOption::PC) => (0b0001, false),
468+
(_, EmitOption::PC) => return Err(DwtError::InvalidFunction),
469+
};
470+
471+
unsafe {
472+
self.function.modify(|mut r| {
473+
r.set_function(function);
474+
r.set_emitrange(emit_range);
475+
// don't compare data value
476+
r.set_datavmatch(false);
477+
// don't compare cycle counter value
478+
// NOTE: only needed for comparator 0, but is SBZP.
479+
r.set_cycmatch(false);
480+
// SBZ as needed, see Page 784/C1-724
481+
r.set_datavsize(0);
482+
r.set_datavaddr0(0);
483+
r.set_datavaddr1(0);
484+
485+
r
486+
});
487+
488+
self.comp.write(settings.address);
489+
self.mask.write(settings.mask);
490+
}
491+
492+
Ok(())
493+
}
494+
}
495+
496+
impl Comparator<NoCycleCompare> {
497+
/// Configure the function of the [`Comparator`]. Does not support cycle count comparison.
409498
#[allow(clippy::missing_inline_in_public_items)]
410499
pub fn configure(&self, settings: ComparatorFunction) -> Result<(), DwtError> {
411500
match settings {
412-
ComparatorFunction::Address(settings) => {
413-
// FUNCTION, EMITRANGE
414-
// See Table C1-14
415-
let (function, emit_range) = match (&settings.access_type, &settings.emit) {
416-
(AccessType::ReadOnly, EmitOption::Data) => (0b1100, false),
417-
(AccessType::ReadOnly, EmitOption::Address) => (0b1100, true),
418-
(AccessType::ReadOnly, EmitOption::AddressData) => (0b1110, true),
419-
(AccessType::ReadOnly, EmitOption::PCData) => (0b1110, false),
420-
(AccessType::ReadOnly, EmitOption::WatchpointDebugEvent) => (0b0101, false),
421-
(AccessType::ReadOnly, EmitOption::CompareMatchEvent) => (0b1001, false),
422-
423-
(AccessType::WriteOnly, EmitOption::Data) => (0b1101, false),
424-
(AccessType::WriteOnly, EmitOption::Address) => (0b1101, true),
425-
(AccessType::WriteOnly, EmitOption::AddressData) => (0b1111, true),
426-
(AccessType::WriteOnly, EmitOption::PCData) => (0b1111, false),
427-
(AccessType::WriteOnly, EmitOption::WatchpointDebugEvent) => (0b0110, false),
428-
(AccessType::WriteOnly, EmitOption::CompareMatchEvent) => (0b1010, false),
429-
430-
(AccessType::ReadWrite, EmitOption::Data) => (0b0010, false),
431-
(AccessType::ReadWrite, EmitOption::Address) => (0b0001, true),
432-
(AccessType::ReadWrite, EmitOption::AddressData) => (0b0010, true),
433-
(AccessType::ReadWrite, EmitOption::PCData) => (0b0011, false),
434-
(AccessType::ReadWrite, EmitOption::WatchpointDebugEvent) => (0b0111, false),
435-
(AccessType::ReadWrite, EmitOption::CompareMatchEvent) => (0b1011, false),
436-
437-
(AccessType::ReadWrite, EmitOption::PC) => (0b0001, false),
438-
(_, EmitOption::PC) => return Err(DwtError::InvalidFunction),
439-
};
440-
441-
unsafe {
442-
self.function.modify(|mut r| {
443-
r.set_function(function);
444-
r.set_emitrange(emit_range);
445-
// don't compare data value
446-
r.set_datavmatch(false);
447-
// don't compare cycle counter value
448-
// NOTE: only needed for comparator 0, but is SBZP.
449-
r.set_cycmatch(false);
450-
// SBZ as needed, see Page 784/C1-724
451-
r.set_datavsize(0);
452-
r.set_datavaddr0(0);
453-
r.set_datavaddr1(0);
454-
455-
r
456-
});
501+
ComparatorFunction::Address(settings) => self.configure_address_compare(settings),
502+
ComparatorFunction::CycleCount(_settings) => Err(DwtError::UnsupportedFunction),
503+
}
504+
}
505+
}
457506

458-
self.comp.write(settings.address);
459-
self.mask.write(settings.mask);
460-
}
461-
}
507+
impl Comparator<HasCycleCompare> {
508+
/// Configure the function of the [`Comparator`]. Has support for cycle count comparison.
509+
#[allow(clippy::missing_inline_in_public_items)]
510+
pub fn configure(&self, settings: ComparatorFunction) -> Result<(), DwtError> {
511+
match settings {
512+
ComparatorFunction::Address(settings) => self.configure_address_compare(settings),
462513
ComparatorFunction::CycleCount(settings) => {
463514
let function = match &settings.emit {
464515
EmitOption::PCData => 0b0001,
@@ -487,9 +538,9 @@ impl Comparator {
487538
self.comp.write(settings.compare);
488539
self.mask.write(0); // SBZ, see Page 784/C1-724
489540
}
541+
542+
Ok(())
490543
}
491544
}
492-
493-
Ok(())
494545
}
495546
}

src/peripheral/test.rs

+15-6
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,21 @@ fn dwt() {
4242
#[cfg(not(armv6m))]
4343
assert_eq!(address(&dwt.foldcnt), 0xE000_1018);
4444
assert_eq!(address(&dwt.pcsr), 0xE000_101C);
45-
assert_eq!(address(&dwt.c[0].comp), 0xE000_1020);
46-
assert_eq!(address(&dwt.c[0].mask), 0xE000_1024);
47-
assert_eq!(address(&dwt.c[0].function), 0xE000_1028);
48-
assert_eq!(address(&dwt.c[1].comp), 0xE000_1030);
49-
assert_eq!(address(&dwt.c[1].mask), 0xE000_1034);
50-
assert_eq!(address(&dwt.c[1].function), 0xE000_1038);
45+
if cfg!(not(armv6m)) {
46+
assert_eq!(address(&dwt.comp0.comp), 0xE000_1020);
47+
assert_eq!(address(&dwt.comp0.mask), 0xE000_1024);
48+
assert_eq!(address(&dwt.comp0.function), 0xE000_1028);
49+
50+
assert_eq!(address(&dwt.comp[0].comp), 0xE000_1030);
51+
assert_eq!(address(&dwt.comp[0].mask), 0xE000_1034);
52+
assert_eq!(address(&dwt.comp[0].function), 0xE000_1038);
53+
}
54+
if cfg!(armv6m) {
55+
assert_eq!(address(&dwt.comp[0].comp), 0xE000_1020);
56+
assert_eq!(address(&dwt.comp[0].mask), 0xE000_1024);
57+
assert_eq!(address(&dwt.comp[0].function), 0xE000_1028);
58+
}
59+
5160
#[cfg(not(armv6m))]
5261
assert_eq!(address(&dwt.lar), 0xE000_1FB0);
5362
#[cfg(not(armv6m))]

0 commit comments

Comments
 (0)