aboutsummaryrefslogtreecommitdiff
path: root/embassy-rp/src/float/functions.rs
diff options
context:
space:
mode:
authorpennae <[email protected]>2023-04-19 01:57:37 +0200
committerpennae <[email protected]>2023-04-19 23:04:47 +0200
commitfdd6e08ed6b5445a53c8cd0752f80f203c4860ac (patch)
tree9b997c5db2d55c911a6fd4cfdce38141e372b762 /embassy-rp/src/float/functions.rs
parenta673b9aa294a55c441f3f61c48481484629b4347 (diff)
rp: hook up softfloat rom intrinsics
rp-hal has done this very well already, so we'll just copy their entire impl again. only div.rs needed some massaging because our sio access works a little differently, everything else worked as is.
Diffstat (limited to 'embassy-rp/src/float/functions.rs')
-rw-r--r--embassy-rp/src/float/functions.rs239
1 files changed, 239 insertions, 0 deletions
diff --git a/embassy-rp/src/float/functions.rs b/embassy-rp/src/float/functions.rs
new file mode 100644
index 000000000..de29ce336
--- /dev/null
+++ b/embassy-rp/src/float/functions.rs
@@ -0,0 +1,239 @@
1// Credit: taken from `rp-hal` (also licensed Apache+MIT)
2// https://github.com/rp-rs/rp-hal/blob/main/rp2040-hal/src/float/functions.rs
3
4use crate::float::{Float, Int};
5use crate::rom_data;
6
7trait ROMFunctions {
8 fn sqrt(self) -> Self;
9 fn ln(self) -> Self;
10 fn exp(self) -> Self;
11 fn sin(self) -> Self;
12 fn cos(self) -> Self;
13 fn tan(self) -> Self;
14 fn atan2(self, y: Self) -> Self;
15
16 fn to_trig_range(self) -> Self;
17}
18
19impl ROMFunctions for f32 {
20 fn sqrt(self) -> Self {
21 rom_data::float_funcs::fsqrt(self)
22 }
23
24 fn ln(self) -> Self {
25 rom_data::float_funcs::fln(self)
26 }
27
28 fn exp(self) -> Self {
29 rom_data::float_funcs::fexp(self)
30 }
31
32 fn sin(self) -> Self {
33 rom_data::float_funcs::fsin(self)
34 }
35
36 fn cos(self) -> Self {
37 rom_data::float_funcs::fcos(self)
38 }
39
40 fn tan(self) -> Self {
41 rom_data::float_funcs::ftan(self)
42 }
43
44 fn atan2(self, y: Self) -> Self {
45 rom_data::float_funcs::fatan2(self, y)
46 }
47
48 fn to_trig_range(self) -> Self {
49 // -128 < X < 128, logic from the Pico SDK
50 let exponent = (self.repr() & Self::EXPONENT_MASK) >> Self::SIGNIFICAND_BITS;
51 if exponent < 134 {
52 self
53 } else {
54 self % (core::f32::consts::PI * 2.0)
55 }
56 }
57}
58
59impl ROMFunctions for f64 {
60 fn sqrt(self) -> Self {
61 rom_data::double_funcs::dsqrt(self)
62 }
63
64 fn ln(self) -> Self {
65 rom_data::double_funcs::dln(self)
66 }
67
68 fn exp(self) -> Self {
69 rom_data::double_funcs::dexp(self)
70 }
71
72 fn sin(self) -> Self {
73 rom_data::double_funcs::dsin(self)
74 }
75
76 fn cos(self) -> Self {
77 rom_data::double_funcs::dcos(self)
78 }
79 fn tan(self) -> Self {
80 rom_data::double_funcs::dtan(self)
81 }
82
83 fn atan2(self, y: Self) -> Self {
84 rom_data::double_funcs::datan2(self, y)
85 }
86
87 fn to_trig_range(self) -> Self {
88 // -1024 < X < 1024, logic from the Pico SDK
89 let exponent = (self.repr() & Self::EXPONENT_MASK) >> Self::SIGNIFICAND_BITS;
90 if exponent < 1033 {
91 self
92 } else {
93 self % (core::f64::consts::PI * 2.0)
94 }
95 }
96}
97
98fn is_negative_nonzero_or_nan<F: Float>(f: F) -> bool {
99 let repr = f.repr();
100 if (repr & F::SIGN_MASK) != F::Int::ZERO {
101 // Negative, so anything other than exactly zero
102 return (repr & (!F::SIGN_MASK)) != F::Int::ZERO;
103 }
104 // NaN
105 (repr & (F::EXPONENT_MASK | F::SIGNIFICAND_MASK)) > F::EXPONENT_MASK
106}
107
108fn sqrt<F: Float + ROMFunctions>(f: F) -> F {
109 if is_negative_nonzero_or_nan(f) {
110 F::NAN
111 } else {
112 f.sqrt()
113 }
114}
115
116fn ln<F: Float + ROMFunctions>(f: F) -> F {
117 if is_negative_nonzero_or_nan(f) {
118 F::NAN
119 } else {
120 f.ln()
121 }
122}
123
124fn exp<F: Float + ROMFunctions>(f: F) -> F {
125 if f.is_nan() {
126 F::NAN
127 } else {
128 f.exp()
129 }
130}
131
132fn sin<F: Float + ROMFunctions>(f: F) -> F {
133 if f.is_not_finite() {
134 F::NAN
135 } else {
136 f.to_trig_range().sin()
137 }
138}
139
140fn cos<F: Float + ROMFunctions>(f: F) -> F {
141 if f.is_not_finite() {
142 F::NAN
143 } else {
144 f.to_trig_range().cos()
145 }
146}
147
148fn tan<F: Float + ROMFunctions>(f: F) -> F {
149 if f.is_not_finite() {
150 F::NAN
151 } else {
152 f.to_trig_range().tan()
153 }
154}
155
156fn atan2<F: Float + ROMFunctions>(x: F, y: F) -> F {
157 if x.is_nan() || y.is_nan() {
158 F::NAN
159 } else {
160 x.to_trig_range().atan2(y)
161 }
162}
163
164// Name collisions
165mod intrinsics {
166 intrinsics! {
167 extern "C" fn sqrtf(f: f32) -> f32 {
168 super::sqrt(f)
169 }
170
171 #[bootrom_v2]
172 extern "C" fn sqrt(f: f64) -> f64 {
173 super::sqrt(f)
174 }
175
176 extern "C" fn logf(f: f32) -> f32 {
177 super::ln(f)
178 }
179
180 #[bootrom_v2]
181 extern "C" fn log(f: f64) -> f64 {
182 super::ln(f)
183 }
184
185 extern "C" fn expf(f: f32) -> f32 {
186 super::exp(f)
187 }
188
189 #[bootrom_v2]
190 extern "C" fn exp(f: f64) -> f64 {
191 super::exp(f)
192 }
193
194 #[slower_than_default]
195 extern "C" fn sinf(f: f32) -> f32 {
196 super::sin(f)
197 }
198
199 #[slower_than_default]
200 #[bootrom_v2]
201 extern "C" fn sin(f: f64) -> f64 {
202 super::sin(f)
203 }
204
205 #[slower_than_default]
206 extern "C" fn cosf(f: f32) -> f32 {
207 super::cos(f)
208 }
209
210 #[slower_than_default]
211 #[bootrom_v2]
212 extern "C" fn cos(f: f64) -> f64 {
213 super::cos(f)
214 }
215
216 #[slower_than_default]
217 extern "C" fn tanf(f: f32) -> f32 {
218 super::tan(f)
219 }
220
221 #[slower_than_default]
222 #[bootrom_v2]
223 extern "C" fn tan(f: f64) -> f64 {
224 super::tan(f)
225 }
226
227 // Questionable gain
228 #[bootrom_v2]
229 extern "C" fn atan2f(a: f32, b: f32) -> f32 {
230 super::atan2(a, b)
231 }
232
233 // Questionable gain
234 #[bootrom_v2]
235 extern "C" fn atan2(a: f64, b: f64) -> f64 {
236 super::atan2(a, b)
237 }
238 }
239}