From 97911d9650308ff0a93893898620360327de4a13 Mon Sep 17 00:00:00 2001 From: Adam Greig Date: Tue, 6 Jun 2017 20:05:40 +0100 Subject: [PATCH 01/15] Add cache control functions for ARMv7-M --- build.rs | 7 +- src/peripheral/mod.rs | 406 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 411 insertions(+), 2 deletions(-) diff --git a/build.rs b/build.rs index f8ad1634..475bd008 100644 --- a/build.rs +++ b/build.rs @@ -4,6 +4,11 @@ fn main() { let target = env::var("TARGET").unwrap(); if target.starts_with("thumbv6m-") { - println!("cargo:rustc-cfg=armv6m") + println!("cargo:rustc-cfg=armv6m"); + } else if target.starts_with("thumbv7m-") { + println!("cargo:rustc-cfg=armv7m"); + } else if target.starts_with("thumbv7em-") { + println!("cargo:rustc-cfg=armv7m"); + println!("cargo:rustc-cfg=armv7em"); } } diff --git a/src/peripheral/mod.rs b/src/peripheral/mod.rs index 1780ee47..89f6f775 100644 --- a/src/peripheral/mod.rs +++ b/src/peripheral/mod.rs @@ -48,6 +48,10 @@ pub const SYST: Peripheral = unsafe { Peripheral::new(0xE000_E010) }; /// Trace Port Interface Unit; pub const TPIU: Peripheral = unsafe { Peripheral::new(0xE004_0000) }; +/// Cache and branch predictor maintenance operations +#[cfg(armv7m)] +pub const CBP: Peripheral = unsafe { Peripheral::new(0xE000_EF50) }; + // TODO stand-alone registers: ICTR, ACTLR and STIR /// A peripheral @@ -100,13 +104,65 @@ pub struct Cpuid { pub isar: [RO; 5], reserved1: u32, /// Cache Level ID + #[cfg(armv7m)] pub clidr: RO, /// Cache Type + #[cfg(armv7m)] pub ctr: RO, /// Cache Size ID + #[cfg(armv7m)] pub ccsidr: RO, /// Cache Size Selection - pub csselr: RO, + #[cfg(armv7m)] + pub csselr: RW, +} + +#[cfg(armv7m)] +const CSSELR_IND_POS: u32 = 0; +#[cfg(armv7m)] +const CSSELR_IND_MASK: u32 = 1 << CSSELR_IND_POS; +#[cfg(armv7m)] +const CSSELR_LEVEL_POS: u32 = 1; +#[cfg(armv7m)] +const CSSELR_LEVEL_MASK: u32 = 0x7 << CSSELR_LEVEL_POS; +#[cfg(armv7m)] +const CCSIDR_NUMSETS_POS: u32 = 13; +#[cfg(armv7m)] +const CCSIDR_NUMSETS_MASK: u32 = 0x7FFF << CCSIDR_NUMSETS_POS; +#[cfg(armv7m)] +const CCSIDR_ASSOCIATIVITY_POS: u32 = 3; +#[cfg(armv7m)] +const CCSIDR_ASSOCIATIVITY_MASK: u32 = 0x3FF << CCSIDR_ASSOCIATIVITY_POS; + + +impl Cpuid { + /// Selects the current CCSIDR + /// + /// * `level`: the required cache level minus 1, e.g. 0 for L1, 1 for L2 + /// * `ind`: select instruction cache (1) or data/unified cache (0) + #[cfg(armv7m)] + pub fn select_cache(&self, level: u32, ind: u32) { + unsafe { self.csselr.write( + ((level << CSSELR_LEVEL_POS) & CSSELR_LEVEL_MASK) | + ((ind << CSSELR_IND_POS) & CSSELR_IND_MASK) + )} + } + + /// Returns the number of sets in the selected cache + #[cfg(armv7m)] + pub fn cache_num_sets(&self, level: u32, ind: u32) -> u32 { + self.select_cache(level, ind); + ::asm::dsb(); + 1 + ((self.ccsidr.read() & CCSIDR_NUMSETS_MASK) >> CCSIDR_NUMSETS_POS) + } + + /// Returns the number of ways in the selected cache + #[cfg(armv7m)] + pub fn cache_num_ways(&self, level: u32, ind: u32) -> u32 { + self.select_cache(level, ind); + ::asm::dsb(); + 1 + ((self.ccsidr.read() & CCSIDR_ASSOCIATIVITY_MASK) >> CCSIDR_ASSOCIATIVITY_POS) + } } /// DCB register block @@ -443,6 +499,11 @@ pub enum FpuAccessMode { Privileged, } +#[cfg(armv7m)] +const SCB_CCR_IC_MASK: u32 = (1<<17); +#[cfg(armv7m)] +const SCB_CCR_DC_MASK: u32 = (1<<16); + const SCB_CPACR_FPU_MASK: u32 = 0x00780000; const SCB_CPACR_FPU_ENABLE: u32 = 0x00280000; const SCB_CPACR_FPU_USER: u32 = 0x00500000; @@ -484,6 +545,230 @@ impl Scb { pub fn disable_fpu(&self) { self.set_fpu_access_mode(FpuAccessMode::Disabled) } + + /// Enables I-Cache + #[cfg(armv7m)] + #[inline] + pub fn enable_icache(&self) { + // All of CBP is write-only so no data races are possible + let cbp = unsafe { &mut *CBP.get() }; + + ::asm::dsb(); + ::asm::isb(); + + // Invalidate I-Cache + cbp.iciallu(); + + // Enable I-Cache + unsafe { self.ccr.modify(|r| r | SCB_CCR_IC_MASK) }; + + ::asm::dsb(); + ::asm::isb(); + } + + /// Disables I-Cache + #[cfg(armv7m)] + #[inline] + pub fn disable_icache(&self) { + // All of CBP is write-only so no data races are possible + let cbp = unsafe { &mut *CBP.get() }; + + ::asm::dsb(); + ::asm::isb(); + + // Disable I-Cache + unsafe { self.ccr.modify(|r| r & !SCB_CCR_IC_MASK) }; + + // Invalidate I-Cache + cbp.iciallu(); + + ::asm::dsb(); + ::asm::isb(); + } + + /// Invalidates I-Cache + #[cfg(armv7m)] + #[inline] + pub fn invalidate_icache(&self) { + // All of CBP is write-only so no data races are possible + let cbp = unsafe { &mut *CBP.get() }; + + ::asm::dsb(); + ::asm::isb(); + + // Invalidate I-Cache + cbp.iciallu(); + + ::asm::dsb(); + ::asm::isb(); + } + + /// Enables D-cache + #[cfg(armv7m)] + #[inline] + pub fn enable_dcache(&self, cpuid: &Cpuid) { + // Invalidate anything currently in the DCache + self.invalidate_dcache(cpuid); + + // Now turn on the DCache + unsafe { self.ccr.modify(|r| r | SCB_CCR_DC_MASK) }; + + ::asm::dsb(); + ::asm::isb(); + } + + /// Disables D-cache + #[cfg(armv7m)] + #[inline] + pub fn disable_dcache(&self, cpuid: &Cpuid) { + // Turn off the DCache + unsafe { self.ccr.modify(|r| r & !SCB_CCR_DC_MASK) }; + + // Clean and invalidate whatever was left in it + self.clean_invalidate_dcache(cpuid); + } + + /// Invalidates D-cache + #[cfg(armv7m)] + #[inline] + pub fn invalidate_dcache(&self, cpuid: &Cpuid) { + // All of CBP is write-only so no data races are possible + let cbp = unsafe { &mut *CBP.get() }; + + // Read number of sets and ways + let sets = cpuid.cache_num_sets(0, 0); + let ways = cpuid.cache_num_ways(0, 0); + + // Invalidate entire D-Cache + for set in 0..sets { + for way in 0..ways { + cbp.dcisw(set, way); + } + } + + ::asm::dsb(); + ::asm::isb(); + } + + /// Cleans D-cache + #[cfg(armv7m)] + #[inline] + pub fn clean_dcache(&self, cpuid: &Cpuid) { + // All of CBP is write-only so no data races are possible + let cbp = unsafe { &mut *CBP.get() }; + + // Read number of sets and ways + let sets = cpuid.cache_num_sets(0, 0); + let ways = cpuid.cache_num_ways(0, 0); + + for set in 0..sets { + for way in 0..ways { + cbp.dccsw(set, way); + } + } + + ::asm::dsb(); + ::asm::isb(); + } + + /// Cleans and invalidates D-cache + #[cfg(armv7m)] + #[inline] + pub fn clean_invalidate_dcache(&self, cpuid: &Cpuid) { + // All of CBP is write-only so no data races are possible + let cbp = unsafe { &mut *CBP.get() }; + + // Read number of sets and ways + let sets = cpuid.cache_num_sets(0, 0); + let ways = cpuid.cache_num_ways(0, 0); + + for set in 0..sets { + for way in 0..ways { + cbp.dccisw(set, way); + } + } + + ::asm::dsb(); + ::asm::isb(); + } + + /// Invalidates D-cache by address + /// + /// `addr`: the address to invalidate, aligned to 32-byte boundary + /// `size`: size of the memory block, in number of bytes, a multiple of 32 + #[cfg(armv7m)] + #[inline] + pub fn invalidate_dcache_by_address(&self, addr: u32, size: u32) { + // All of CBP is write-only so no data races are possible + let cbp = unsafe { &mut *CBP.get() }; + + ::asm::dsb(); + + // Cache lines are fixed to 32 bit on Cortex-M7 and not present in earlier Cortex-M + const LINESIZE: u32 = 32; + + let mut addr = addr; + + for _ in 0..(size/LINESIZE) { + cbp.dcimvac(addr); + addr += LINESIZE; + } + + ::asm::dsb(); + ::asm::isb(); + } + + /// Cleans D-cache by address + /// + /// `addr`: the address to clean, aligned to 32-byte boundary + /// `size`: size of the memory block, in number of bytes, a multiple of 32 + #[cfg(armv7m)] + #[inline] + pub fn clean_dcache_by_address(&self, addr: u32, size: u32) { + // All of CBP is write-only so no data races are possible + let cbp = unsafe { &mut *CBP.get() }; + + ::asm::dsb(); + + // Cache lines are fixed to 32 bit on Cortex-M7 and not present in earlier Cortex-M + const LINESIZE: u32 = 32; + + let mut addr = addr; + + for _ in 0..(size/LINESIZE) { + cbp.dccmvac(addr); + addr += LINESIZE; + } + + ::asm::dsb(); + ::asm::isb(); + } + + /// Cleans and invalidates D-cache by address + /// + /// `addr`: the address to clean and invalidate, aligned to 32-byte boundary + /// `size`: size of the memory block, in number of bytes, a multiple of 32 + #[cfg(armv7m)] + #[inline] + pub fn clean_invalidate_dcache_by_address(&self, addr: u32, size: u32) { + // All of CBP is write-only so no data races are possible + let cbp = unsafe { &mut *CBP.get() }; + + ::asm::dsb(); + + // Cache lines are fixed to 32 bit on Cortex-M7 and not present in earlier Cortex-M + const LINESIZE: u32 = 32; + + let mut addr = addr; + + for _ in 0..(size/LINESIZE) { + cbp.dccimvac(addr); + addr += LINESIZE; + } + + ::asm::dsb(); + ::asm::isb(); + } } /// SysTick register block @@ -646,3 +931,122 @@ pub struct Tpiu { /// TPIU Type pub _type: RO, } + +/// Cache and branch predictor maintenance operations register block +#[repr(C)] +#[cfg(armv7m)] +pub struct Cbp { + /// I-cache invalidate all to PoU + pub iciallu: WO, + reserved0: RW, + /// I-cache invalidate by MVA to PoU + pub icimvau: WO, + /// D-cache invalidate by MVA to PoC + pub dcimvac: WO, + /// D-cache invalidate by set-way + pub dcisw: WO, + /// D-cache clean by MVA to PoU + pub dccmvau: WO, + /// D-cache clean by MVA to PoC + pub dccmvac: WO, + /// D-cache clean by set-way + pub dccsw: WO, + /// D-cache clean and invalidate by MVA to PoC + pub dccimvac: WO, + /// D-cache clean and invalidate by set-way + pub dccisw: WO, + /// Branch predictor invalidate all + pub bpiall: WO, +} + +#[cfg(armv7m)] +const CBP_SW_WAY_POS: u32 = 30; +#[cfg(armv7m)] +const CBP_SW_WAY_MASK: u32 = 0x3 << CBP_SW_WAY_POS; +#[cfg(armv7m)] +const CBP_SW_SET_POS: u32 = 5; +#[cfg(armv7m)] +const CBP_SW_SET_MASK: u32 = 0x1FF << CBP_SW_SET_POS; + +#[cfg(armv7m)] +impl Cbp { + /// I-cache invalidate all to PoU + #[inline(always)] + pub fn iciallu(&self) { + unsafe { self.iciallu.write(0); } + } + + /// I-cache invalidate by MVA to PoU + #[inline(always)] + pub fn icimvau(&self, mva: u32) { + unsafe { self.icimvau.write(mva); } + } + + /// D-cache invalidate by MVA to PoC + #[inline(always)] + pub fn dcimvac(&self, mva: u32) { + unsafe { self.dcimvac.write(mva); } + } + + /// D-cache invalidate by set-way + #[inline(always)] + pub fn dcisw(&self, set: u32, way: u32) { + // The ARMv7-M Architecture Reference Manual, as of Revision E.b, says these set/way + // operations have a register data format which depends on the implementation's + // associativity and number of sets. Specifically the 'way' and 'set' fields have + // offsets 32-log2(ASSOCIATIVITY) and log2(LINELEN) respectively. + // + // However, in Cortex-M7 devices, these offsets are fixed at 30 and 5, as per the Cortex-M7 + // Generic User Guide section 4.8.3. Since no other ARMv7-M implementations except the + // Cortex-M7 have a DCACHE or ICACHE at all, it seems safe to do the same thing as the + // CMSIS-Core implementation and use fixed values. + unsafe { self.dcisw.write( + ((way << CBP_SW_WAY_POS) & CBP_SW_WAY_MASK) | + ((set << CBP_SW_SET_POS) & CBP_SW_SET_MASK)); + } + } + + /// D-cache clean by MVA to PoU + #[inline(always)] + pub fn dccmvau(&self, mva: u32) { + unsafe { self.dccmvau.write(mva); } + } + + /// D-cache clean by MVA to PoC + #[inline(always)] + pub fn dccmvac(&self, mva: u32) { + unsafe { self.dccmvac.write(mva); } + } + + /// D-cache clean by set-way + #[inline(always)] + pub fn dccsw(&self, set: u32, way: u32) { + // See comment for dcisw() about the format here + unsafe { self.dccsw.write( + ((way << CBP_SW_WAY_POS) & CBP_SW_WAY_MASK) | + ((set << CBP_SW_SET_POS) & CBP_SW_SET_MASK)); + } + } + + /// D-cache clean and invalidate by MVA to PoC + #[inline(always)] + pub fn dccimvac(&self, mva: u32) { + unsafe { self.dccimvac.write(mva); } + } + + /// D-cache clean and invalidate by set-way + #[inline(always)] + pub fn dccisw(&self, set: u32, way: u32) { + // See comment for dcisw() about the format here + unsafe { self.dccisw.write( + ((way << CBP_SW_WAY_POS) & CBP_SW_WAY_MASK) | + ((set << CBP_SW_SET_POS) & CBP_SW_SET_MASK)); + } + } + + /// Branch predictor invalidate all + #[inline(always)] + pub fn bpiall(&self) { + unsafe { self.bpiall.write(0); } + } +} From 07c40422eb0a6967847a9abbd34b00f99c2b119c Mon Sep 17 00:00:00 2001 From: Adam Greig Date: Mon, 12 Jun 2017 11:53:31 +0100 Subject: [PATCH 02/15] Combine cache_num_sets and cache_num_ways into single read of CCSIDR --- src/peripheral/mod.rs | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/src/peripheral/mod.rs b/src/peripheral/mod.rs index ac0bf756..5be57606 100644 --- a/src/peripheral/mod.rs +++ b/src/peripheral/mod.rs @@ -148,20 +148,14 @@ impl Cpuid { )} } - /// Returns the number of sets in the selected cache + /// Returns the number of sets and ways in the selected cache #[cfg(armv7m)] - pub fn cache_num_sets(&self, level: u32, ind: u32) -> u32 { + pub fn cache_num_sets_ways(&self, level: u32, ind: u32) -> (u32, u32) { self.select_cache(level, ind); ::asm::dsb(); - 1 + ((self.ccsidr.read() & CCSIDR_NUMSETS_MASK) >> CCSIDR_NUMSETS_POS) - } - - /// Returns the number of ways in the selected cache - #[cfg(armv7m)] - pub fn cache_num_ways(&self, level: u32, ind: u32) -> u32 { - self.select_cache(level, ind); - ::asm::dsb(); - 1 + ((self.ccsidr.read() & CCSIDR_ASSOCIATIVITY_MASK) >> CCSIDR_ASSOCIATIVITY_POS) + let ccsidr = self.ccsidr.read(); + (1 + ((ccsidr & CCSIDR_NUMSETS_MASK) >> CCSIDR_NUMSETS_POS), + 1 + ((ccsidr & CCSIDR_ASSOCIATIVITY_MASK) >> CCSIDR_ASSOCIATIVITY_POS)) } } @@ -636,8 +630,7 @@ impl Scb { let cbp = unsafe { &mut *CBP.get() }; // Read number of sets and ways - let sets = cpuid.cache_num_sets(0, 0); - let ways = cpuid.cache_num_ways(0, 0); + let (sets, ways) = cpuid.cache_num_sets_ways(0, 0); // Invalidate entire D-Cache for set in 0..sets { @@ -658,8 +651,7 @@ impl Scb { let cbp = unsafe { &mut *CBP.get() }; // Read number of sets and ways - let sets = cpuid.cache_num_sets(0, 0); - let ways = cpuid.cache_num_ways(0, 0); + let (sets, ways) = cpuid.cache_num_sets_ways(0, 0); for set in 0..sets { for way in 0..ways { @@ -679,8 +671,7 @@ impl Scb { let cbp = unsafe { &mut *CBP.get() }; // Read number of sets and ways - let sets = cpuid.cache_num_sets(0, 0); - let ways = cpuid.cache_num_ways(0, 0); + let (sets, ways) = cpuid.cache_num_sets_ways(0, 0); for set in 0..sets { for way in 0..ways { From 414422f3a893c3a4795b22f7767858a90529c3f7 Mon Sep 17 00:00:00 2001 From: Adam Greig Date: Mon, 12 Jun 2017 11:57:25 +0100 Subject: [PATCH 03/15] Make invalidate_dcache private --- src/peripheral/mod.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/peripheral/mod.rs b/src/peripheral/mod.rs index 5be57606..48842238 100644 --- a/src/peripheral/mod.rs +++ b/src/peripheral/mod.rs @@ -623,9 +623,13 @@ impl Scb { } /// Invalidates D-cache + /// + /// Note that calling this while the dcache is enabled will probably wipe out your + /// stack, depending on optimisations, breaking returning to the call point. + /// It's used immediately before enabling the dcache, but not exported publicly. #[cfg(armv7m)] #[inline] - pub fn invalidate_dcache(&self, cpuid: &Cpuid) { + fn invalidate_dcache(&self, cpuid: &Cpuid) { // All of CBP is write-only so no data races are possible let cbp = unsafe { &mut *CBP.get() }; From 7a2de260c5428e835dbce2d0d5e4539d218904a4 Mon Sep 17 00:00:00 2001 From: Adam Greig Date: Mon, 12 Jun 2017 12:17:30 +0100 Subject: [PATCH 04/15] Tidy up cfg(armv7m) use --- src/peripheral/mod.rs | 29 +++-------------------------- 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/src/peripheral/mod.rs b/src/peripheral/mod.rs index 48842238..198840ef 100644 --- a/src/peripheral/mod.rs +++ b/src/peripheral/mod.rs @@ -117,24 +117,15 @@ pub struct Cpuid { pub csselr: RW, } -#[cfg(armv7m)] const CSSELR_IND_POS: u32 = 0; -#[cfg(armv7m)] const CSSELR_IND_MASK: u32 = 1 << CSSELR_IND_POS; -#[cfg(armv7m)] const CSSELR_LEVEL_POS: u32 = 1; -#[cfg(armv7m)] const CSSELR_LEVEL_MASK: u32 = 0x7 << CSSELR_LEVEL_POS; -#[cfg(armv7m)] const CCSIDR_NUMSETS_POS: u32 = 13; -#[cfg(armv7m)] const CCSIDR_NUMSETS_MASK: u32 = 0x7FFF << CCSIDR_NUMSETS_POS; -#[cfg(armv7m)] const CCSIDR_ASSOCIATIVITY_POS: u32 = 3; -#[cfg(armv7m)] const CCSIDR_ASSOCIATIVITY_MASK: u32 = 0x3FF << CCSIDR_ASSOCIATIVITY_POS; - impl Cpuid { /// Selects the current CCSIDR /// @@ -493,9 +484,7 @@ pub enum FpuAccessMode { Privileged, } -#[cfg(armv7m)] const SCB_CCR_IC_MASK: u32 = (1<<17); -#[cfg(armv7m)] const SCB_CCR_DC_MASK: u32 = (1<<16); const SCB_CPACR_FPU_MASK: u32 = 0b11_11 << 20; @@ -539,9 +528,11 @@ impl Scb { pub fn disable_fpu(&self) { self.set_fpu_access_mode(FpuAccessMode::Disabled) } +} +#[cfg(armv7m)] +impl Scb { /// Enables I-Cache - #[cfg(armv7m)] #[inline] pub fn enable_icache(&self) { // All of CBP is write-only so no data races are possible @@ -561,7 +552,6 @@ impl Scb { } /// Disables I-Cache - #[cfg(armv7m)] #[inline] pub fn disable_icache(&self) { // All of CBP is write-only so no data races are possible @@ -581,7 +571,6 @@ impl Scb { } /// Invalidates I-Cache - #[cfg(armv7m)] #[inline] pub fn invalidate_icache(&self) { // All of CBP is write-only so no data races are possible @@ -598,7 +587,6 @@ impl Scb { } /// Enables D-cache - #[cfg(armv7m)] #[inline] pub fn enable_dcache(&self, cpuid: &Cpuid) { // Invalidate anything currently in the DCache @@ -612,7 +600,6 @@ impl Scb { } /// Disables D-cache - #[cfg(armv7m)] #[inline] pub fn disable_dcache(&self, cpuid: &Cpuid) { // Turn off the DCache @@ -627,7 +614,6 @@ impl Scb { /// Note that calling this while the dcache is enabled will probably wipe out your /// stack, depending on optimisations, breaking returning to the call point. /// It's used immediately before enabling the dcache, but not exported publicly. - #[cfg(armv7m)] #[inline] fn invalidate_dcache(&self, cpuid: &Cpuid) { // All of CBP is write-only so no data races are possible @@ -648,7 +634,6 @@ impl Scb { } /// Cleans D-cache - #[cfg(armv7m)] #[inline] pub fn clean_dcache(&self, cpuid: &Cpuid) { // All of CBP is write-only so no data races are possible @@ -668,7 +653,6 @@ impl Scb { } /// Cleans and invalidates D-cache - #[cfg(armv7m)] #[inline] pub fn clean_invalidate_dcache(&self, cpuid: &Cpuid) { // All of CBP is write-only so no data races are possible @@ -691,7 +675,6 @@ impl Scb { /// /// `addr`: the address to invalidate, aligned to 32-byte boundary /// `size`: size of the memory block, in number of bytes, a multiple of 32 - #[cfg(armv7m)] #[inline] pub fn invalidate_dcache_by_address(&self, addr: u32, size: u32) { // All of CBP is write-only so no data races are possible @@ -717,7 +700,6 @@ impl Scb { /// /// `addr`: the address to clean, aligned to 32-byte boundary /// `size`: size of the memory block, in number of bytes, a multiple of 32 - #[cfg(armv7m)] #[inline] pub fn clean_dcache_by_address(&self, addr: u32, size: u32) { // All of CBP is write-only so no data races are possible @@ -743,7 +725,6 @@ impl Scb { /// /// `addr`: the address to clean and invalidate, aligned to 32-byte boundary /// `size`: size of the memory block, in number of bytes, a multiple of 32 - #[cfg(armv7m)] #[inline] pub fn clean_invalidate_dcache_by_address(&self, addr: u32, size: u32) { // All of CBP is write-only so no data races are possible @@ -954,13 +935,9 @@ pub struct Cbp { pub bpiall: WO, } -#[cfg(armv7m)] const CBP_SW_WAY_POS: u32 = 30; -#[cfg(armv7m)] const CBP_SW_WAY_MASK: u32 = 0x3 << CBP_SW_WAY_POS; -#[cfg(armv7m)] const CBP_SW_SET_POS: u32 = 5; -#[cfg(armv7m)] const CBP_SW_SET_MASK: u32 = 0x1FF << CBP_SW_SET_POS; #[cfg(armv7m)] From c7c391dfee5ccd141211766549ffafc4a5862b6b Mon Sep 17 00:00:00 2001 From: Adam Greig Date: Mon, 12 Jun 2017 12:30:46 +0100 Subject: [PATCH 05/15] Use enum for ind on CSSELR --- src/peripheral/mod.rs | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/peripheral/mod.rs b/src/peripheral/mod.rs index 198840ef..5dd49e93 100644 --- a/src/peripheral/mod.rs +++ b/src/peripheral/mod.rs @@ -126,22 +126,31 @@ const CCSIDR_NUMSETS_MASK: u32 = 0x7FFF << CCSIDR_NUMSETS_POS; const CCSIDR_ASSOCIATIVITY_POS: u32 = 3; const CCSIDR_ASSOCIATIVITY_MASK: u32 = 0x3FF << CCSIDR_ASSOCIATIVITY_POS; +/// Type of cache to select on CSSELR writes. +#[cfg(armv7m)] +pub enum CsselrCacheType { + /// Select DCache or unified cache + DataOrUnified = 0, + /// Select ICache + Instruction = 1, +} + +#[cfg(armv7m)] impl Cpuid { /// Selects the current CCSIDR /// /// * `level`: the required cache level minus 1, e.g. 0 for L1, 1 for L2 - /// * `ind`: select instruction cache (1) or data/unified cache (0) - #[cfg(armv7m)] - pub fn select_cache(&self, level: u32, ind: u32) { + /// * `ind`: select instruction cache or data/unified cache + pub fn select_cache(&self, level: u8, ind: CsselrCacheType) { + assert!(level<8); unsafe { self.csselr.write( - ((level << CSSELR_LEVEL_POS) & CSSELR_LEVEL_MASK) | - ((ind << CSSELR_IND_POS) & CSSELR_IND_MASK) + (((level as u32) << CSSELR_LEVEL_POS) & CSSELR_LEVEL_MASK) | + (((ind as u32) << CSSELR_IND_POS) & CSSELR_IND_MASK) )} } /// Returns the number of sets and ways in the selected cache - #[cfg(armv7m)] - pub fn cache_num_sets_ways(&self, level: u32, ind: u32) -> (u32, u32) { + pub fn cache_num_sets_ways(&self, level: u8, ind: CsselrCacheType) -> (u32, u32) { self.select_cache(level, ind); ::asm::dsb(); let ccsidr = self.ccsidr.read(); @@ -620,7 +629,7 @@ impl Scb { let cbp = unsafe { &mut *CBP.get() }; // Read number of sets and ways - let (sets, ways) = cpuid.cache_num_sets_ways(0, 0); + let (sets, ways) = cpuid.cache_num_sets_ways(0, CsselrCacheType::DataOrUnified); // Invalidate entire D-Cache for set in 0..sets { @@ -640,7 +649,7 @@ impl Scb { let cbp = unsafe { &mut *CBP.get() }; // Read number of sets and ways - let (sets, ways) = cpuid.cache_num_sets_ways(0, 0); + let (sets, ways) = cpuid.cache_num_sets_ways(0, CsselrCacheType::DataOrUnified); for set in 0..sets { for way in 0..ways { @@ -659,7 +668,7 @@ impl Scb { let cbp = unsafe { &mut *CBP.get() }; // Read number of sets and ways - let (sets, ways) = cpuid.cache_num_sets_ways(0, 0); + let (sets, ways) = cpuid.cache_num_sets_ways(0, CsselrCacheType::DataOrUnified); for set in 0..sets { for way in 0..ways { From a5170ebda241cf3eb5bb95bf7a75b7b96df74714 Mon Sep 17 00:00:00 2001 From: Adam Greig Date: Mon, 12 Jun 2017 12:31:19 +0100 Subject: [PATCH 06/15] Use u16 for number of cache sets/ways --- src/peripheral/mod.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/peripheral/mod.rs b/src/peripheral/mod.rs index 5dd49e93..0d81b496 100644 --- a/src/peripheral/mod.rs +++ b/src/peripheral/mod.rs @@ -150,12 +150,12 @@ impl Cpuid { } /// Returns the number of sets and ways in the selected cache - pub fn cache_num_sets_ways(&self, level: u8, ind: CsselrCacheType) -> (u32, u32) { + pub fn cache_num_sets_ways(&self, level: u8, ind: CsselrCacheType) -> (u16, u16) { self.select_cache(level, ind); ::asm::dsb(); let ccsidr = self.ccsidr.read(); - (1 + ((ccsidr & CCSIDR_NUMSETS_MASK) >> CCSIDR_NUMSETS_POS), - 1 + ((ccsidr & CCSIDR_ASSOCIATIVITY_MASK) >> CCSIDR_ASSOCIATIVITY_POS)) + ((1 + ((ccsidr & CCSIDR_NUMSETS_MASK) >> CCSIDR_NUMSETS_POS)) as u16, + (1 + ((ccsidr & CCSIDR_ASSOCIATIVITY_MASK) >> CCSIDR_ASSOCIATIVITY_POS)) as u16) } } @@ -971,7 +971,7 @@ impl Cbp { /// D-cache invalidate by set-way #[inline(always)] - pub fn dcisw(&self, set: u32, way: u32) { + pub fn dcisw(&self, set: u16, way: u16) { // The ARMv7-M Architecture Reference Manual, as of Revision E.b, says these set/way // operations have a register data format which depends on the implementation's // associativity and number of sets. Specifically the 'way' and 'set' fields have @@ -982,8 +982,8 @@ impl Cbp { // Cortex-M7 have a DCACHE or ICACHE at all, it seems safe to do the same thing as the // CMSIS-Core implementation and use fixed values. unsafe { self.dcisw.write( - ((way << CBP_SW_WAY_POS) & CBP_SW_WAY_MASK) | - ((set << CBP_SW_SET_POS) & CBP_SW_SET_MASK)); + (((way as u32) << CBP_SW_WAY_POS) & CBP_SW_WAY_MASK) | + (((set as u32) << CBP_SW_SET_POS) & CBP_SW_SET_MASK)); } } @@ -1001,11 +1001,11 @@ impl Cbp { /// D-cache clean by set-way #[inline(always)] - pub fn dccsw(&self, set: u32, way: u32) { + pub fn dccsw(&self, set: u16, way: u16) { // See comment for dcisw() about the format here unsafe { self.dccsw.write( - ((way << CBP_SW_WAY_POS) & CBP_SW_WAY_MASK) | - ((set << CBP_SW_SET_POS) & CBP_SW_SET_MASK)); + (((way as u32) << CBP_SW_WAY_POS) & CBP_SW_WAY_MASK) | + (((set as u32) << CBP_SW_SET_POS) & CBP_SW_SET_MASK)); } } @@ -1017,11 +1017,11 @@ impl Cbp { /// D-cache clean and invalidate by set-way #[inline(always)] - pub fn dccisw(&self, set: u32, way: u32) { + pub fn dccisw(&self, set: u16, way: u16) { // See comment for dcisw() about the format here unsafe { self.dccisw.write( - ((way << CBP_SW_WAY_POS) & CBP_SW_WAY_MASK) | - ((set << CBP_SW_SET_POS) & CBP_SW_SET_MASK)); + (((way as u32) << CBP_SW_WAY_POS) & CBP_SW_WAY_MASK) | + (((set as u32) << CBP_SW_SET_POS) & CBP_SW_SET_MASK)); } } From 861c0896001ffbb5bbe57cd69177df183ca9819c Mon Sep 17 00:00:00 2001 From: Adam Greig Date: Mon, 12 Jun 2017 12:37:09 +0100 Subject: [PATCH 07/15] Document behaviour of cache _by_address methods better --- src/peripheral/mod.rs | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/peripheral/mod.rs b/src/peripheral/mod.rs index 0d81b496..65a82a7e 100644 --- a/src/peripheral/mod.rs +++ b/src/peripheral/mod.rs @@ -682,8 +682,11 @@ impl Scb { /// Invalidates D-cache by address /// - /// `addr`: the address to invalidate, aligned to 32-byte boundary - /// `size`: size of the memory block, in number of bytes, a multiple of 32 + /// `addr`: the address to invalidate + /// `size`: size of the memory block, in number of bytes + /// + /// Invalidates cache starting from the lowest 32-byte aligned address represented by `addr`, + /// in blocks of 32 bytes until at least `size` bytes have been invalidated. #[inline] pub fn invalidate_dcache_by_address(&self, addr: u32, size: u32) { // All of CBP is write-only so no data races are possible @@ -691,10 +694,11 @@ impl Scb { ::asm::dsb(); + // Cache lines are fixed to 32 bit on Cortex-M7 and not present in earlier Cortex-M const LINESIZE: u32 = 32; - let mut addr = addr; + let mut addr = addr & 0xFFFF_FFE0; for _ in 0..(size/LINESIZE) { cbp.dcimvac(addr); @@ -707,8 +711,11 @@ impl Scb { /// Cleans D-cache by address /// - /// `addr`: the address to clean, aligned to 32-byte boundary - /// `size`: size of the memory block, in number of bytes, a multiple of 32 + /// `addr`: the address to clean + /// `size`: size of the memory block, in number of bytes + /// + /// Cleans cache starting from the lowest 32-byte aligned address represented by `addr`, + /// in blocks of 32 bytes until at least `size` bytes have been cleaned. #[inline] pub fn clean_dcache_by_address(&self, addr: u32, size: u32) { // All of CBP is write-only so no data races are possible @@ -719,7 +726,7 @@ impl Scb { // Cache lines are fixed to 32 bit on Cortex-M7 and not present in earlier Cortex-M const LINESIZE: u32 = 32; - let mut addr = addr; + let mut addr = addr & 0xFFFF_FFE0; for _ in 0..(size/LINESIZE) { cbp.dccmvac(addr); @@ -732,8 +739,12 @@ impl Scb { /// Cleans and invalidates D-cache by address /// - /// `addr`: the address to clean and invalidate, aligned to 32-byte boundary - /// `size`: size of the memory block, in number of bytes, a multiple of 32 + /// `addr`: the address to clean and invalidate + /// `size`: size of the memory block, in number of bytes + /// + /// Cleans and invalidates cache starting from the lowest 32-byte aligned address represented + /// by `addr`, in blocks of 32 bytes until at least `size` bytes have been cleaned and + /// invalidated. #[inline] pub fn clean_invalidate_dcache_by_address(&self, addr: u32, size: u32) { // All of CBP is write-only so no data races are possible @@ -744,7 +755,7 @@ impl Scb { // Cache lines are fixed to 32 bit on Cortex-M7 and not present in earlier Cortex-M const LINESIZE: u32 = 32; - let mut addr = addr; + let mut addr = addr & 0xFFFF_FFE0; for _ in 0..(size/LINESIZE) { cbp.dccimvac(addr); From c442c1cb2bfdef634d24a6b00cd4d559f2dfb7fa Mon Sep 17 00:00:00 2001 From: Adam Greig Date: Mon, 12 Jun 2017 12:38:21 +0100 Subject: [PATCH 08/15] Comment out armv7em cfg flag until it's needed --- build.rs | 2 +- src/peripheral/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.rs b/build.rs index 475bd008..1f6d605f 100644 --- a/build.rs +++ b/build.rs @@ -9,6 +9,6 @@ fn main() { println!("cargo:rustc-cfg=armv7m"); } else if target.starts_with("thumbv7em-") { println!("cargo:rustc-cfg=armv7m"); - println!("cargo:rustc-cfg=armv7em"); + //println!("cargo:rustc-cfg=armv7em"); } } diff --git a/src/peripheral/mod.rs b/src/peripheral/mod.rs index 65a82a7e..2dcfa30e 100644 --- a/src/peripheral/mod.rs +++ b/src/peripheral/mod.rs @@ -934,7 +934,7 @@ pub struct Tpiu { pub struct Cbp { /// I-cache invalidate all to PoU pub iciallu: WO, - reserved0: RW, + reserved0: u32, /// I-cache invalidate by MVA to PoU pub icimvau: WO, /// D-cache invalidate by MVA to PoC From bd0a100ebf0a012a95e12d3070fa01e7a5b3658c Mon Sep 17 00:00:00 2001 From: Adam Greig Date: Tue, 13 Jun 2017 20:41:15 +0100 Subject: [PATCH 09/15] Add icache_enabled and dcache_enabled methods to SCB --- src/peripheral/mod.rs | 53 ++++++++++++++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/src/peripheral/mod.rs b/src/peripheral/mod.rs index 2dcfa30e..b85f6995 100644 --- a/src/peripheral/mod.rs +++ b/src/peripheral/mod.rs @@ -541,15 +541,17 @@ impl Scb { #[cfg(armv7m)] impl Scb { - /// Enables I-Cache + /// Enables I-Cache if currently disabled #[inline] pub fn enable_icache(&self) { + // Don't do anything if ICache is already enabled + if self.icache_enabled() { + return; + } + // All of CBP is write-only so no data races are possible let cbp = unsafe { &mut *CBP.get() }; - ::asm::dsb(); - ::asm::isb(); - // Invalidate I-Cache cbp.iciallu(); @@ -560,15 +562,17 @@ impl Scb { ::asm::isb(); } - /// Disables I-Cache + /// Disables I-Cache if currently enabled #[inline] pub fn disable_icache(&self) { + // Don't do anything if ICache is already disabled + if !self.icache_enabled() { + return; + } + // All of CBP is write-only so no data races are possible let cbp = unsafe { &mut *CBP.get() }; - ::asm::dsb(); - ::asm::isb(); - // Disable I-Cache unsafe { self.ccr.modify(|r| r & !SCB_CCR_IC_MASK) }; @@ -579,15 +583,20 @@ impl Scb { ::asm::isb(); } + /// Returns whether the I-Cache is currently enabled + #[inline] + pub fn icache_enabled(&self) -> bool { + ::asm::dsb(); + ::asm::isb(); + self.ccr.read() & SCB_CCR_IC_MASK == SCB_CCR_IC_MASK + } + /// Invalidates I-Cache #[inline] pub fn invalidate_icache(&self) { // All of CBP is write-only so no data races are possible let cbp = unsafe { &mut *CBP.get() }; - ::asm::dsb(); - ::asm::isb(); - // Invalidate I-Cache cbp.iciallu(); @@ -595,9 +604,14 @@ impl Scb { ::asm::isb(); } - /// Enables D-cache + /// Enables D-cache if currently disabled #[inline] pub fn enable_dcache(&self, cpuid: &Cpuid) { + // Don't do anything if DCache is already enabled + if self.dcache_enabled() { + return; + } + // Invalidate anything currently in the DCache self.invalidate_dcache(cpuid); @@ -608,9 +622,14 @@ impl Scb { ::asm::isb(); } - /// Disables D-cache + /// Disables D-cache if currently enabled #[inline] pub fn disable_dcache(&self, cpuid: &Cpuid) { + // Don't do anything if DCache is already disabled + if !self.dcache_enabled() { + return; + } + // Turn off the DCache unsafe { self.ccr.modify(|r| r & !SCB_CCR_DC_MASK) }; @@ -618,6 +637,14 @@ impl Scb { self.clean_invalidate_dcache(cpuid); } + /// Returns whether the D-Cache is currently enabled + #[inline] + pub fn dcache_enabled(&self) -> bool { + ::asm::dsb(); + ::asm::isb(); + self.ccr.read() & SCB_CCR_DC_MASK == SCB_CCR_DC_MASK + } + /// Invalidates D-cache /// /// Note that calling this while the dcache is enabled will probably wipe out your From ea7ce5c3b0e38c5c8c9fe4e71860b830e30f22ba Mon Sep 17 00:00:00 2001 From: Adam Greig Date: Wed, 14 Jun 2017 23:38:11 +0100 Subject: [PATCH 10/15] Remove config flags on CPUID fields. This prevents these changes being breaking changes as these fields used to be exposed. To be re-added in a future breaking release. --- src/peripheral/mod.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/peripheral/mod.rs b/src/peripheral/mod.rs index b85f6995..1c71e110 100644 --- a/src/peripheral/mod.rs +++ b/src/peripheral/mod.rs @@ -104,16 +104,12 @@ pub struct Cpuid { pub isar: [RO; 5], reserved1: u32, /// Cache Level ID - #[cfg(armv7m)] pub clidr: RO, /// Cache Type - #[cfg(armv7m)] pub ctr: RO, /// Cache Size ID - #[cfg(armv7m)] pub ccsidr: RO, /// Cache Size Selection - #[cfg(armv7m)] pub csselr: RW, } From 45896618a3d012811015ec265cfb512c8d6458eb Mon Sep 17 00:00:00 2001 From: Adam Greig Date: Wed, 14 Jun 2017 23:45:26 +0100 Subject: [PATCH 11/15] Don't assert(level<8), just note that we mask it --- src/peripheral/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/peripheral/mod.rs b/src/peripheral/mod.rs index 1c71e110..235dbe38 100644 --- a/src/peripheral/mod.rs +++ b/src/peripheral/mod.rs @@ -137,8 +137,9 @@ impl Cpuid { /// /// * `level`: the required cache level minus 1, e.g. 0 for L1, 1 for L2 /// * `ind`: select instruction cache or data/unified cache + /// + /// `level` is masked to be between 0 and 7. pub fn select_cache(&self, level: u8, ind: CsselrCacheType) { - assert!(level<8); unsafe { self.csselr.write( (((level as u32) << CSSELR_LEVEL_POS) & CSSELR_LEVEL_MASK) | (((ind as u32) << CSSELR_IND_POS) & CSSELR_IND_MASK) From aa3e5d04305db00101967bca330956b13162faa6 Mon Sep 17 00:00:00 2001 From: Adam Greig Date: Wed, 14 Jun 2017 23:47:33 +0100 Subject: [PATCH 12/15] Add documentation note about set and way masking for CBP methods --- src/peripheral/mod.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/peripheral/mod.rs b/src/peripheral/mod.rs index 235dbe38..d04a320e 100644 --- a/src/peripheral/mod.rs +++ b/src/peripheral/mod.rs @@ -1005,6 +1005,8 @@ impl Cbp { } /// D-cache invalidate by set-way + /// + /// `set` is masked to be between 0 and 3, and `way` between 0 and 511. #[inline(always)] pub fn dcisw(&self, set: u16, way: u16) { // The ARMv7-M Architecture Reference Manual, as of Revision E.b, says these set/way @@ -1035,6 +1037,8 @@ impl Cbp { } /// D-cache clean by set-way + /// + /// `set` is masked to be between 0 and 3, and `way` between 0 and 511. #[inline(always)] pub fn dccsw(&self, set: u16, way: u16) { // See comment for dcisw() about the format here @@ -1051,6 +1055,8 @@ impl Cbp { } /// D-cache clean and invalidate by set-way + /// + /// `set` is masked to be between 0 and 3, and `way` between 0 and 511. #[inline(always)] pub fn dccisw(&self, set: u16, way: u16) { // See comment for dcisw() about the format here From da097d8ac51a773d3f33c6263f1c263025390657 Mon Sep 17 00:00:00 2001 From: Adam Greig Date: Thu, 15 Jun 2017 00:06:36 +0100 Subject: [PATCH 13/15] Mask set and way parameters before shifting to prevent overflow --- src/peripheral/mod.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/peripheral/mod.rs b/src/peripheral/mod.rs index d04a320e..15e4a470 100644 --- a/src/peripheral/mod.rs +++ b/src/peripheral/mod.rs @@ -1019,8 +1019,8 @@ impl Cbp { // Cortex-M7 have a DCACHE or ICACHE at all, it seems safe to do the same thing as the // CMSIS-Core implementation and use fixed values. unsafe { self.dcisw.write( - (((way as u32) << CBP_SW_WAY_POS) & CBP_SW_WAY_MASK) | - (((set as u32) << CBP_SW_SET_POS) & CBP_SW_SET_MASK)); + (((way as u32) & (CBP_SW_WAY_MASK >> CBP_SW_WAY_POS)) << CBP_SW_WAY_POS) | + (((set as u32) & (CBP_SW_SET_MASK >> CBP_SW_SET_POS)) << CBP_SW_SET_POS)); } } @@ -1043,8 +1043,8 @@ impl Cbp { pub fn dccsw(&self, set: u16, way: u16) { // See comment for dcisw() about the format here unsafe { self.dccsw.write( - (((way as u32) << CBP_SW_WAY_POS) & CBP_SW_WAY_MASK) | - (((set as u32) << CBP_SW_SET_POS) & CBP_SW_SET_MASK)); + (((way as u32) & (CBP_SW_WAY_MASK >> CBP_SW_WAY_POS)) << CBP_SW_WAY_POS) | + (((set as u32) & (CBP_SW_SET_MASK >> CBP_SW_SET_POS)) << CBP_SW_SET_POS)); } } @@ -1061,8 +1061,8 @@ impl Cbp { pub fn dccisw(&self, set: u16, way: u16) { // See comment for dcisw() about the format here unsafe { self.dccisw.write( - (((way as u32) << CBP_SW_WAY_POS) & CBP_SW_WAY_MASK) | - (((set as u32) << CBP_SW_SET_POS) & CBP_SW_SET_MASK)); + (((way as u32) & (CBP_SW_WAY_MASK >> CBP_SW_WAY_POS)) << CBP_SW_WAY_POS) | + (((set as u32) & (CBP_SW_SET_MASK >> CBP_SW_SET_POS)) << CBP_SW_SET_POS)); } } From 8f42e8fe816d34976e17ed3affb1846efa3bfcde Mon Sep 17 00:00:00 2001 From: Adam Greig Date: Thu, 15 Jun 2017 00:06:41 +0100 Subject: [PATCH 14/15] Fix number of cache lines invalidated for sizes not a multiple of 32 --- src/peripheral/mod.rs | 43 ++++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/src/peripheral/mod.rs b/src/peripheral/mod.rs index 15e4a470..ad8be319 100644 --- a/src/peripheral/mod.rs +++ b/src/peripheral/mod.rs @@ -712,20 +712,25 @@ impl Scb { /// Invalidates cache starting from the lowest 32-byte aligned address represented by `addr`, /// in blocks of 32 bytes until at least `size` bytes have been invalidated. #[inline] - pub fn invalidate_dcache_by_address(&self, addr: u32, size: u32) { + pub fn invalidate_dcache_by_address(&self, addr: usize, size: usize) { + // No-op zero sized operations + if size == 0 { + return; + } + // All of CBP is write-only so no data races are possible let cbp = unsafe { &mut *CBP.get() }; ::asm::dsb(); - // Cache lines are fixed to 32 bit on Cortex-M7 and not present in earlier Cortex-M - const LINESIZE: u32 = 32; + const LINESIZE: usize = 32; + let num_lines = ((size - 1)/LINESIZE) + 1; let mut addr = addr & 0xFFFF_FFE0; - for _ in 0..(size/LINESIZE) { - cbp.dcimvac(addr); + for _ in 0..num_lines { + cbp.dcimvac(addr as u32); addr += LINESIZE; } @@ -741,19 +746,25 @@ impl Scb { /// Cleans cache starting from the lowest 32-byte aligned address represented by `addr`, /// in blocks of 32 bytes until at least `size` bytes have been cleaned. #[inline] - pub fn clean_dcache_by_address(&self, addr: u32, size: u32) { + pub fn clean_dcache_by_address(&self, addr: usize, size: usize) { + // No-op zero sized operations + if size == 0 { + return; + } + // All of CBP is write-only so no data races are possible let cbp = unsafe { &mut *CBP.get() }; ::asm::dsb(); // Cache lines are fixed to 32 bit on Cortex-M7 and not present in earlier Cortex-M - const LINESIZE: u32 = 32; + const LINESIZE: usize = 32; + let num_lines = ((size - 1)/LINESIZE) + 1; let mut addr = addr & 0xFFFF_FFE0; - for _ in 0..(size/LINESIZE) { - cbp.dccmvac(addr); + for _ in 0..num_lines { + cbp.dccmvac(addr as u32); addr += LINESIZE; } @@ -770,19 +781,25 @@ impl Scb { /// by `addr`, in blocks of 32 bytes until at least `size` bytes have been cleaned and /// invalidated. #[inline] - pub fn clean_invalidate_dcache_by_address(&self, addr: u32, size: u32) { + pub fn clean_invalidate_dcache_by_address(&self, addr: usize, size: usize) { + // No-op zero sized operations + if size == 0 { + return; + } + // All of CBP is write-only so no data races are possible let cbp = unsafe { &mut *CBP.get() }; ::asm::dsb(); // Cache lines are fixed to 32 bit on Cortex-M7 and not present in earlier Cortex-M - const LINESIZE: u32 = 32; + const LINESIZE: usize = 32; + let num_lines = ((size - 1)/LINESIZE) + 1; let mut addr = addr & 0xFFFF_FFE0; - for _ in 0..(size/LINESIZE) { - cbp.dccimvac(addr); + for _ in 0..num_lines { + cbp.dccimvac(addr as u32); addr += LINESIZE; } From 0947e742959911e2693dc78542659978eaab9264 Mon Sep 17 00:00:00 2001 From: Adam Greig Date: Thu, 15 Jun 2017 03:30:32 +0100 Subject: [PATCH 15/15] Move ARMv7-M specific constants into a cfg-gated module --- src/peripheral/mod.rs | 45 ++++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/src/peripheral/mod.rs b/src/peripheral/mod.rs index ad8be319..1b21bc54 100644 --- a/src/peripheral/mod.rs +++ b/src/peripheral/mod.rs @@ -113,15 +113,6 @@ pub struct Cpuid { pub csselr: RW, } -const CSSELR_IND_POS: u32 = 0; -const CSSELR_IND_MASK: u32 = 1 << CSSELR_IND_POS; -const CSSELR_LEVEL_POS: u32 = 1; -const CSSELR_LEVEL_MASK: u32 = 0x7 << CSSELR_LEVEL_POS; -const CCSIDR_NUMSETS_POS: u32 = 13; -const CCSIDR_NUMSETS_MASK: u32 = 0x7FFF << CCSIDR_NUMSETS_POS; -const CCSIDR_ASSOCIATIVITY_POS: u32 = 3; -const CCSIDR_ASSOCIATIVITY_MASK: u32 = 0x3FF << CCSIDR_ASSOCIATIVITY_POS; - /// Type of cache to select on CSSELR writes. #[cfg(armv7m)] pub enum CsselrCacheType { @@ -140,6 +131,11 @@ impl Cpuid { /// /// `level` is masked to be between 0 and 7. pub fn select_cache(&self, level: u8, ind: CsselrCacheType) { + const CSSELR_IND_POS: u32 = 0; + const CSSELR_IND_MASK: u32 = 1 << CSSELR_IND_POS; + const CSSELR_LEVEL_POS: u32 = 1; + const CSSELR_LEVEL_MASK: u32 = 0x7 << CSSELR_LEVEL_POS; + unsafe { self.csselr.write( (((level as u32) << CSSELR_LEVEL_POS) & CSSELR_LEVEL_MASK) | (((ind as u32) << CSSELR_IND_POS) & CSSELR_IND_MASK) @@ -148,6 +144,11 @@ impl Cpuid { /// Returns the number of sets and ways in the selected cache pub fn cache_num_sets_ways(&self, level: u8, ind: CsselrCacheType) -> (u16, u16) { + const CCSIDR_NUMSETS_POS: u32 = 13; + const CCSIDR_NUMSETS_MASK: u32 = 0x7FFF << CCSIDR_NUMSETS_POS; + const CCSIDR_ASSOCIATIVITY_POS: u32 = 3; + const CCSIDR_ASSOCIATIVITY_MASK: u32 = 0x3FF << CCSIDR_ASSOCIATIVITY_POS; + self.select_cache(level, ind); ::asm::dsb(); let ccsidr = self.ccsidr.read(); @@ -490,9 +491,6 @@ pub enum FpuAccessMode { Privileged, } -const SCB_CCR_IC_MASK: u32 = (1<<17); -const SCB_CCR_DC_MASK: u32 = (1<<16); - const SCB_CPACR_FPU_MASK: u32 = 0b11_11 << 20; const SCB_CPACR_FPU_ENABLE: u32 = 0b01_01 << 20; const SCB_CPACR_FPU_USER: u32 = 0b10_10 << 20; @@ -536,6 +534,15 @@ impl Scb { } } +#[cfg(armv7m)] +mod scb_consts { + pub const SCB_CCR_IC_MASK: u32 = (1<<17); + pub const SCB_CCR_DC_MASK: u32 = (1<<16); +} + +#[cfg(armv7m)] +use self::scb_consts::*; + #[cfg(armv7m)] impl Scb { /// Enables I-Cache if currently disabled @@ -996,10 +1003,16 @@ pub struct Cbp { pub bpiall: WO, } -const CBP_SW_WAY_POS: u32 = 30; -const CBP_SW_WAY_MASK: u32 = 0x3 << CBP_SW_WAY_POS; -const CBP_SW_SET_POS: u32 = 5; -const CBP_SW_SET_MASK: u32 = 0x1FF << CBP_SW_SET_POS; +#[cfg(armv7m)] +mod cbp_consts { + pub const CBP_SW_WAY_POS: u32 = 30; + pub const CBP_SW_WAY_MASK: u32 = 0x3 << CBP_SW_WAY_POS; + pub const CBP_SW_SET_POS: u32 = 5; + pub const CBP_SW_SET_MASK: u32 = 0x1FF << CBP_SW_SET_POS; +} + +#[cfg(armv7m)] +use self::cbp_consts::*; #[cfg(armv7m)] impl Cbp {