Skip to content

Commit 9e263cc

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 rust-embedded#376
1 parent b0d2d03 commit 9e263cc

File tree

2 files changed

+122
-62
lines changed

2 files changed

+122
-62
lines changed

src/peripheral/dwt.rs

Lines changed: 107 additions & 56 deletions
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! {
@@ -414,63 +440,88 @@ pub enum ComparatorFunction {
414440
pub enum DwtError {
415441
/// Invalid combination of [AccessType] and [EmitOption].
416442
InvalidFunction,
443+
/// An unsupported function was requested, such as [`CycleCount`](ComparatorFunction::CycleCount) on
444+
/// `armv6m`, or on a comparator other than 0 on `armv7m`.
445+
UnsupportedFunction,
417446
}
418447

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

470-
self.comp.write(settings.address);
471-
self.mask.write(settings.mask);
472-
}
473-
}
519+
impl Comparator<HasCycleCompare> {
520+
/// Configure the function of the [`Comparator`]. Has support for cycle count comparison.
521+
#[allow(clippy::missing_inline_in_public_items)]
522+
pub fn configure(&self, settings: ComparatorFunction) -> Result<(), DwtError> {
523+
match settings {
524+
ComparatorFunction::Address(settings) => self.configure_address_compare(settings),
474525
ComparatorFunction::CycleCount(settings) => {
475526
let function = match &settings.emit {
476527
EmitOption::PCData => 0b0001,
@@ -499,9 +550,9 @@ impl Comparator {
499550
self.comp.write(settings.compare);
500551
self.mask.write(0); // SBZ, see Page 784/C1-724
501552
}
553+
554+
Ok(())
502555
}
503556
}
504-
505-
Ok(())
506557
}
507558
}

src/peripheral/test.rs

Lines changed: 15 additions & 6 deletions
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)