1 | //! Cache and branch predictor maintenance operations |
2 | //! |
3 | //! *NOTE* Not available on Armv6-M. |
4 | |
5 | use volatile_register::WO; |
6 | |
7 | use crate::peripheral::CBP; |
8 | |
9 | /// Register block |
10 | #[repr (C)] |
11 | pub struct RegisterBlock { |
12 | /// I-cache invalidate all to PoU |
13 | pub iciallu: WO<u32>, |
14 | reserved0: u32, |
15 | /// I-cache invalidate by MVA to PoU |
16 | pub icimvau: WO<u32>, |
17 | /// D-cache invalidate by MVA to PoC |
18 | pub dcimvac: WO<u32>, |
19 | /// D-cache invalidate by set-way |
20 | pub dcisw: WO<u32>, |
21 | /// D-cache clean by MVA to PoU |
22 | pub dccmvau: WO<u32>, |
23 | /// D-cache clean by MVA to PoC |
24 | pub dccmvac: WO<u32>, |
25 | /// D-cache clean by set-way |
26 | pub dccsw: WO<u32>, |
27 | /// D-cache clean and invalidate by MVA to PoC |
28 | pub dccimvac: WO<u32>, |
29 | /// D-cache clean and invalidate by set-way |
30 | pub dccisw: WO<u32>, |
31 | /// Branch predictor invalidate all |
32 | pub bpiall: WO<u32>, |
33 | } |
34 | |
35 | const CBP_SW_WAY_POS: u32 = 30; |
36 | const CBP_SW_WAY_MASK: u32 = 0x3 << CBP_SW_WAY_POS; |
37 | const CBP_SW_SET_POS: u32 = 5; |
38 | const CBP_SW_SET_MASK: u32 = 0x1FF << CBP_SW_SET_POS; |
39 | |
40 | impl CBP { |
41 | /// I-cache invalidate all to PoU |
42 | #[inline (always)] |
43 | pub fn iciallu(&mut self) { |
44 | unsafe { self.iciallu.write(0) }; |
45 | } |
46 | |
47 | /// I-cache invalidate by MVA to PoU |
48 | #[inline (always)] |
49 | pub fn icimvau(&mut self, mva: u32) { |
50 | unsafe { self.icimvau.write(mva) }; |
51 | } |
52 | |
53 | /// D-cache invalidate by MVA to PoC |
54 | #[inline (always)] |
55 | pub unsafe fn dcimvac(&mut self, mva: u32) { |
56 | self.dcimvac.write(mva); |
57 | } |
58 | |
59 | /// D-cache invalidate by set-way |
60 | /// |
61 | /// `set` is masked to be between 0 and 3, and `way` between 0 and 511. |
62 | #[inline (always)] |
63 | pub unsafe fn dcisw(&mut self, set: u16, way: u16) { |
64 | // The ARMv7-M Architecture Reference Manual, as of Revision E.b, says these set/way |
65 | // operations have a register data format which depends on the implementation's |
66 | // associativity and number of sets. Specifically the 'way' and 'set' fields have |
67 | // offsets 32-log2(ASSOCIATIVITY) and log2(LINELEN) respectively. |
68 | // |
69 | // However, in Cortex-M7 devices, these offsets are fixed at 30 and 5, as per the Cortex-M7 |
70 | // Generic User Guide section 4.8.3. Since no other ARMv7-M implementations except the |
71 | // Cortex-M7 have a DCACHE or ICACHE at all, it seems safe to do the same thing as the |
72 | // CMSIS-Core implementation and use fixed values. |
73 | self.dcisw.write( |
74 | ((u32::from(way) & (CBP_SW_WAY_MASK >> CBP_SW_WAY_POS)) << CBP_SW_WAY_POS) |
75 | | ((u32::from(set) & (CBP_SW_SET_MASK >> CBP_SW_SET_POS)) << CBP_SW_SET_POS), |
76 | ); |
77 | } |
78 | |
79 | /// D-cache clean by MVA to PoU |
80 | #[inline (always)] |
81 | pub fn dccmvau(&mut self, mva: u32) { |
82 | unsafe { |
83 | self.dccmvau.write(mva); |
84 | } |
85 | } |
86 | |
87 | /// D-cache clean by MVA to PoC |
88 | #[inline (always)] |
89 | pub fn dccmvac(&mut self, mva: u32) { |
90 | unsafe { |
91 | self.dccmvac.write(mva); |
92 | } |
93 | } |
94 | |
95 | /// D-cache clean by set-way |
96 | /// |
97 | /// `set` is masked to be between 0 and 3, and `way` between 0 and 511. |
98 | #[inline (always)] |
99 | pub fn dccsw(&mut self, set: u16, way: u16) { |
100 | // See comment for dcisw() about the format here |
101 | unsafe { |
102 | self.dccsw.write( |
103 | ((u32::from(way) & (CBP_SW_WAY_MASK >> CBP_SW_WAY_POS)) << CBP_SW_WAY_POS) |
104 | | ((u32::from(set) & (CBP_SW_SET_MASK >> CBP_SW_SET_POS)) << CBP_SW_SET_POS), |
105 | ); |
106 | } |
107 | } |
108 | |
109 | /// D-cache clean and invalidate by MVA to PoC |
110 | #[inline (always)] |
111 | pub fn dccimvac(&mut self, mva: u32) { |
112 | unsafe { |
113 | self.dccimvac.write(mva); |
114 | } |
115 | } |
116 | |
117 | /// D-cache clean and invalidate by set-way |
118 | /// |
119 | /// `set` is masked to be between 0 and 3, and `way` between 0 and 511. |
120 | #[inline (always)] |
121 | pub fn dccisw(&mut self, set: u16, way: u16) { |
122 | // See comment for dcisw() about the format here |
123 | unsafe { |
124 | self.dccisw.write( |
125 | ((u32::from(way) & (CBP_SW_WAY_MASK >> CBP_SW_WAY_POS)) << CBP_SW_WAY_POS) |
126 | | ((u32::from(set) & (CBP_SW_SET_MASK >> CBP_SW_SET_POS)) << CBP_SW_SET_POS), |
127 | ); |
128 | } |
129 | } |
130 | |
131 | /// Branch predictor invalidate all |
132 | #[inline (always)] |
133 | pub fn bpiall(&mut self) { |
134 | unsafe { |
135 | self.bpiall.write(0); |
136 | } |
137 | } |
138 | } |
139 | |