Skip to content

Commit 5e75716

Browse files
bors[bot]bugadaniDániel Buga
authored
220: Implement accessing FPSCR r=adamgreig a=bugadani On the nRF52, sometimes it is necessary to manipulate the FPSCR register, otherwise the device wakes up immediately from sleep. (At least on this device) the FPSCR is only available through `vmrs` instructions. I've implemented reading the register, parsing its bits and writing a raw value to the register, but let me know if I should also implement manipulation of the named bits. I would also like to request some assistance to get this to actually build, it's not clear to me how `.s` files are compiled in this library. I'm also not certain where the actual place for this would be - in the registers, or in the `fpu` module. Co-authored-by: Dániel Buga <[email protected]> Co-authored-by: Dániel Buga <[email protected]>
2 parents 1c9d36e + 9062f34 commit 5e75716

11 files changed

+378
-3
lines changed

asm-fpu.s

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
.cfi_sections .debug_frame
2+
3+
.section .text.__get_FPSCR
4+
.global __get_FPSCR
5+
.thumb_func
6+
.cfi_startproc
7+
__get_FPSCR:
8+
vmrs r0, fpscr
9+
bx lr
10+
.cfi_endproc
11+
.size __get_FPSCR, . - __get_FPSCR
12+
13+
.section .text.__set_FPSCR
14+
.global __set_FPSCR
15+
.thumb_func
16+
.cfi_startproc
17+
__set_FPSCR:
18+
vmsr fpscr, r0
19+
bx lr
20+
.cfi_endproc
21+
.size __set_FPSCR, . - __set_FPSCR

assemble.sh

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,11 @@ arm-none-eabi-as -g -march=armv7-m asm-v7.s -o bin/$crate-v7.o
1717
ar crs bin/thumbv7m-none-eabi.a bin/$crate.o bin/$crate-v7.o
1818

1919
arm-none-eabi-as -g -march=armv7e-m asm.s -o bin/$crate.o
20-
arm-none-eabi-as -g -march=armv7e-m asm-v7.s -o bin/$crate-v7.o
20+
arm-none-eabi-as -g -march=armv7e-m asm-fpu.s -mfpu=fpv4-sp-d16 -o bin/$crate-v7-fpu.o
2121
arm-none-eabi-as -g -march=armv7e-m asm-cm7-r0p1.s -o bin/$crate-cm7-r0p1.o
22+
arm-none-eabi-as -g -march=armv7e-m asm-v7.s -o bin/$crate-v7.o
2223
ar crs bin/thumbv7em-none-eabi.a bin/$crate.o bin/$crate-v7.o bin/$crate-cm7-r0p1.o
23-
ar crs bin/thumbv7em-none-eabihf.a bin/$crate.o bin/$crate-v7.o bin/$crate-cm7-r0p1.o
24+
ar crs bin/thumbv7em-none-eabihf.a bin/$crate.o bin/$crate-v7.o bin/$crate-cm7-r0p1.o bin/$crate-v7-fpu.o
2425

2526
arm-none-eabi-as -g -march=armv8-m.base asm.s -o bin/$crate.o
2627
arm-none-eabi-as -g -march=armv8-m.base asm-v8.s -o bin/$crate-v8.o
@@ -30,11 +31,14 @@ arm-none-eabi-as -g -march=armv8-m.main asm.s -o bin/$crate.o
3031
arm-none-eabi-as -g -march=armv8-m.main asm-v7.s -o bin/$crate-v7.o
3132
arm-none-eabi-as -g -march=armv8-m.main asm-v8.s -o bin/$crate-v8.o
3233
arm-none-eabi-as -g -march=armv8-m.main asm-v8-main.s -o bin/$crate-v8-main.o
34+
arm-none-eabi-as -g -march=armv8-m.main asm-fpu.s -mfpu=fpv5-sp-d16 -o bin/$crate-v8-fpu.o
3335
ar crs bin/thumbv8m.main-none-eabi.a bin/$crate.o bin/$crate-v7.o bin/$crate-v8.o bin/$crate-v8-main.o
34-
ar crs bin/thumbv8m.main-none-eabihf.a bin/$crate.o bin/$crate-v7.o bin/$crate-v8.o bin/$crate-v8-main.o
36+
ar crs bin/thumbv8m.main-none-eabihf.a bin/$crate.o bin/$crate-v7.o bin/$crate-v8.o bin/$crate-v8-main.o bin/$crate-v8-fpu.o
3537

3638
rm bin/$crate.o
3739
rm bin/$crate-v7.o
40+
rm bin/$crate-v7-fpu.o
41+
rm bin/$crate-v8-fpu.o
3842
rm bin/$crate-cm7-r0p1.o
3943
rm bin/$crate-v8.o
4044
rm bin/$crate-v8-main.o

bin/thumbv6m-none-eabi.a

0 Bytes
Binary file not shown.

bin/thumbv7em-none-eabi.a

-16 Bytes
Binary file not shown.

bin/thumbv7em-none-eabihf.a

2 KB
Binary file not shown.

bin/thumbv7m-none-eabi.a

-8 Bytes
Binary file not shown.

bin/thumbv8m.base-none-eabi.a

-8 Bytes
Binary file not shown.

bin/thumbv8m.main-none-eabi.a

-16 Bytes
Binary file not shown.

bin/thumbv8m.main-none-eabihf.a

2 KB
Binary file not shown.

src/register/fpscr.rs

Lines changed: 343 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,343 @@
1+
//! Floating-point Status Control Register
2+
3+
/// Floating-point Status Control Register
4+
#[allow(clippy::missing_inline_in_public_items)]
5+
#[derive(Clone, Copy, Debug)]
6+
pub struct Fpscr {
7+
bits: u32,
8+
}
9+
10+
impl Fpscr {
11+
/// Creates a `Fspcr` value from raw bits.
12+
#[inline]
13+
pub fn from_bits(bits: u32) -> Self {
14+
Self { bits }
15+
}
16+
17+
/// Returns the contents of the register as raw bits
18+
#[inline]
19+
pub fn bits(self) -> u32 {
20+
self.bits
21+
}
22+
23+
/// Read the Negative condition code flag
24+
#[inline]
25+
pub fn n(self) -> bool {
26+
self.bits & (1 << 31) != 0
27+
}
28+
29+
/// Sets the Negative condition code flag
30+
#[inline]
31+
pub fn set_n(&mut self, n: bool) {
32+
let mask = 1 << 31;
33+
match n {
34+
true => self.bits |= mask,
35+
false => self.bits &= !mask,
36+
}
37+
}
38+
39+
/// Read the Zero condition code flag
40+
#[inline]
41+
pub fn z(self) -> bool {
42+
self.bits & (1 << 30) != 0
43+
}
44+
45+
/// Sets the Zero condition code flag
46+
#[inline]
47+
pub fn set_z(&mut self, z: bool) {
48+
let mask = 1 << 30;
49+
match z {
50+
true => self.bits |= mask,
51+
false => self.bits &= !mask,
52+
}
53+
}
54+
55+
/// Read the Carry condition code flag
56+
#[inline]
57+
pub fn c(self) -> bool {
58+
self.bits & (1 << 29) != 0
59+
}
60+
61+
/// Sets the Carry condition code flag
62+
#[inline]
63+
pub fn set_c(&mut self, c: bool) {
64+
let mask = 1 << 29;
65+
match c {
66+
true => self.bits |= mask,
67+
false => self.bits &= !mask,
68+
}
69+
}
70+
71+
/// Read the Overflow condition code flag
72+
#[inline]
73+
pub fn v(self) -> bool {
74+
self.bits & (1 << 28) != 0
75+
}
76+
77+
/// Sets the Zero condition code flag
78+
#[inline]
79+
pub fn set_v(&mut self, v: bool) {
80+
let mask = 1 << 28;
81+
match v {
82+
true => self.bits |= mask,
83+
false => self.bits &= !mask,
84+
}
85+
}
86+
87+
/// Read the Alternative Half Precision bit
88+
#[inline]
89+
pub fn ahp(self) -> bool {
90+
self.bits & (1 << 26) != 0
91+
}
92+
93+
/// Sets the Alternative Half Precision bit
94+
#[inline]
95+
pub fn set_ahp(&mut self, ahp: bool) {
96+
let mask = 1 << 26;
97+
match ahp {
98+
true => self.bits |= mask,
99+
false => self.bits &= !mask,
100+
}
101+
}
102+
103+
/// Read the Default NaN mode bit
104+
#[inline]
105+
pub fn dn(self) -> bool {
106+
self.bits & (1 << 25) != 0
107+
}
108+
109+
/// Sets the Default NaN mode bit
110+
#[inline]
111+
pub fn set_dn(&mut self, dn: bool) {
112+
let mask = 1 << 25;
113+
match dn {
114+
true => self.bits |= mask,
115+
false => self.bits &= !mask,
116+
}
117+
}
118+
119+
/// Read the Flush to Zero mode bit
120+
#[inline]
121+
pub fn fz(self) -> bool {
122+
self.bits & (1 << 24) != 0
123+
}
124+
125+
/// Sets the Flush to Zero mode bit
126+
#[inline]
127+
pub fn set_fz(&mut self, fz: bool) {
128+
let mask = 1 << 24;
129+
match fz {
130+
true => self.bits |= mask,
131+
false => self.bits &= !mask,
132+
}
133+
}
134+
135+
/// Read the Rounding Mode control field
136+
#[inline]
137+
pub fn rmode(self) -> RMode {
138+
match (self.bits & (3 << 22)) >> 22 {
139+
0 => RMode::Nearest,
140+
1 => RMode::PlusInfinity,
141+
2 => RMode::MinusInfinity,
142+
_ => RMode::Zero,
143+
}
144+
}
145+
146+
/// Sets the Rounding Mode control field
147+
#[inline]
148+
pub fn set_rmode(&mut self, rmode: RMode) {
149+
let mask = 3 << 22;
150+
match rmode {
151+
RMode::Nearest => self.bits = self.bits & !mask,
152+
RMode::PlusInfinity => self.bits = (self.bits & !mask) | (1 << 22),
153+
RMode::MinusInfinity => self.bits = (self.bits & !mask) | (2 << 22),
154+
RMode::Zero => self.bits = self.bits | mask,
155+
}
156+
}
157+
158+
/// Read the Input Denormal cumulative exception bit
159+
#[inline]
160+
pub fn idc(self) -> bool {
161+
self.bits & (1 << 7) != 0
162+
}
163+
164+
/// Sets the Input Denormal cumulative exception bit
165+
#[inline]
166+
pub fn set_idc(&mut self, idc: bool) {
167+
let mask = 1 << 7;
168+
match idc {
169+
true => self.bits |= mask,
170+
false => self.bits &= !mask,
171+
}
172+
}
173+
174+
/// Read the Inexact cumulative exception bit
175+
#[inline]
176+
pub fn ixc(self) -> bool {
177+
self.bits & (1 << 4) != 0
178+
}
179+
180+
/// Sets the Inexact cumulative exception bit
181+
#[inline]
182+
pub fn set_ixc(&mut self, ixc: bool) {
183+
let mask = 1 << 4;
184+
match ixc {
185+
true => self.bits |= mask,
186+
false => self.bits &= !mask,
187+
}
188+
}
189+
190+
/// Read the Underflow cumulative exception bit
191+
#[inline]
192+
pub fn ufc(self) -> bool {
193+
self.bits & (1 << 3) != 0
194+
}
195+
196+
/// Sets the Underflow cumulative exception bit
197+
#[inline]
198+
pub fn set_ufc(&mut self, ufc: bool) {
199+
let mask = 1 << 3;
200+
match ufc {
201+
true => self.bits |= mask,
202+
false => self.bits &= !mask,
203+
}
204+
}
205+
206+
/// Read the Overflow cumulative exception bit
207+
#[inline]
208+
pub fn ofc(self) -> bool {
209+
self.bits & (1 << 2) != 0
210+
}
211+
212+
/// Sets the Overflow cumulative exception bit
213+
#[inline]
214+
pub fn set_ofc(&mut self, ofc: bool) {
215+
let mask = 1 << 2;
216+
match ofc {
217+
true => self.bits |= mask,
218+
false => self.bits &= !mask,
219+
}
220+
}
221+
222+
/// Read the Division by Zero cumulative exception bit
223+
#[inline]
224+
pub fn dzc(self) -> bool {
225+
self.bits & (1 << 1) != 0
226+
}
227+
228+
/// Sets the Division by Zero cumulative exception bit
229+
#[inline]
230+
pub fn set_dzc(&mut self, dzc: bool) {
231+
let mask = 1 << 1;
232+
match dzc {
233+
true => self.bits |= mask,
234+
false => self.bits &= !mask,
235+
}
236+
}
237+
238+
/// Read the Invalid Operation cumulative exception bit
239+
#[inline]
240+
pub fn ioc(self) -> bool {
241+
self.bits & (1 << 0) != 0
242+
}
243+
244+
/// Sets the Invalid Operation cumulative exception bit
245+
#[inline]
246+
pub fn set_ioc(&mut self, ioc: bool) {
247+
let mask = 1 << 0;
248+
match ioc {
249+
true => self.bits |= mask,
250+
false => self.bits &= !mask,
251+
}
252+
}
253+
}
254+
255+
/// Rounding mode
256+
#[allow(clippy::missing_inline_in_public_items)]
257+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
258+
pub enum RMode {
259+
/// Round to Nearest (RN) mode. This is the reset value.
260+
Nearest,
261+
/// Round towards Plus Infinity (RP) mode.
262+
PlusInfinity,
263+
/// Round towards Minus Infinity (RM) mode.
264+
MinusInfinity,
265+
/// Round towards Zero (RZ) mode.
266+
Zero,
267+
}
268+
269+
impl RMode {
270+
/// Is Nearest the current rounding mode?
271+
#[inline]
272+
pub fn is_nearest(self) -> bool {
273+
self == RMode::Nearest
274+
}
275+
276+
/// Is Plus Infinity the current rounding mode?
277+
#[inline]
278+
pub fn is_plus_infinity(self) -> bool {
279+
self == RMode::PlusInfinity
280+
}
281+
282+
/// Is Minus Infinity the current rounding mode?
283+
#[inline]
284+
pub fn is_minus_infinity(self) -> bool {
285+
self == RMode::MinusInfinity
286+
}
287+
288+
/// Is Zero the current rounding mode?
289+
#[inline]
290+
pub fn is_zero(self) -> bool {
291+
self == RMode::Zero
292+
}
293+
}
294+
295+
/// Read the FPSCR register
296+
#[inline]
297+
pub fn read() -> Fpscr {
298+
match () {
299+
#[cfg(all(cortex_m, feature = "inline-asm"))]
300+
() => {
301+
let r: u32;
302+
unsafe {
303+
llvm_asm!("vmrs $0, fpscr" : "=r"(r) ::: "volatile");
304+
}
305+
Fpscr::from_bits(r)
306+
}
307+
308+
#[cfg(all(cortex_m, not(feature = "inline-asm")))]
309+
() => unsafe {
310+
extern "C" {
311+
fn __get_FPSCR() -> u32;
312+
}
313+
Fpscr::from_bits(__get_FPSCR())
314+
},
315+
316+
#[cfg(not(cortex_m))]
317+
() => unimplemented!(),
318+
}
319+
}
320+
321+
/// Set the value of the FPSCR register
322+
#[inline]
323+
pub unsafe fn write(_fspcr: Fpscr) {
324+
match () {
325+
#[cfg(all(cortex_m, feature = "inline-asm"))]
326+
() => {
327+
let bits = _fspcr.bits();
328+
llvm_asm!("vmsr fpscr, $0" :: "r"(bits) :: "volatile");
329+
}
330+
331+
#[cfg(all(cortex_m, not(feature = "inline-asm")))]
332+
() => {
333+
extern "C" {
334+
fn __set_FPSCR(bits: u32);
335+
}
336+
337+
__set_FPSCR(_fspcr.bits());
338+
}
339+
340+
#[cfg(not(cortex_m))]
341+
() => unimplemented!(),
342+
}
343+
}

0 commit comments

Comments
 (0)