1use crate::{Float, RoundingMode, F128, F32, F64};
2use softfloat_sys_riscv::float16_t;
3use std::borrow::Borrow;
4use std::cmp::Ordering;
5
6#[derive(Copy, Clone, Debug)]
8pub struct F16(float16_t);
9
10impl Float for F16 {
11 type Payload = u16;
12
13 const EXPONENT_BIT: Self::Payload = 0x1f;
14 const FRACTION_BIT: Self::Payload = 0x3ff;
15 const SIGN_POS: usize = 15;
16 const EXPONENT_POS: usize = 10;
17
18 #[inline]
19 fn set_payload(&mut self, x: Self::Payload) {
20 self.0.v = x;
21 }
22
23 #[inline]
24 fn from_bits(v: Self::Payload) -> Self {
25 Self(float16_t { v })
26 }
27
28 #[inline]
29 fn bits(&self) -> Self::Payload {
30 self.0.v
31 }
32
33 fn add<T: Borrow<Self>>(&self, x: T, rnd: RoundingMode) -> Self {
34 rnd.set();
35 let ret = unsafe { softfloat_sys_riscv::f16_add(self.0, x.borrow().0) };
36 Self(ret)
37 }
38
39 fn sub<T: Borrow<Self>>(&self, x: T, rnd: RoundingMode) -> Self {
40 rnd.set();
41 let ret = unsafe { softfloat_sys_riscv::f16_sub(self.0, x.borrow().0) };
42 Self(ret)
43 }
44
45 fn mul<T: Borrow<Self>>(&self, x: T, rnd: RoundingMode) -> Self {
46 rnd.set();
47 let ret = unsafe { softfloat_sys_riscv::f16_mul(self.0, x.borrow().0) };
48 Self(ret)
49 }
50
51 fn fused_mul_add<T: Borrow<Self>>(&self, x: T, y: T, rnd: RoundingMode) -> Self {
52 rnd.set();
53 let ret = unsafe { softfloat_sys_riscv::f16_mulAdd(self.0, x.borrow().0, y.borrow().0) };
54 Self(ret)
55 }
56
57 fn div<T: Borrow<Self>>(&self, x: T, rnd: RoundingMode) -> Self {
58 rnd.set();
59 let ret = unsafe { softfloat_sys_riscv::f16_div(self.0, x.borrow().0) };
60 Self(ret)
61 }
62
63 fn rem<T: Borrow<Self>>(&self, x: T, rnd: RoundingMode) -> Self {
64 rnd.set();
65 let ret = unsafe { softfloat_sys_riscv::f16_rem(self.0, x.borrow().0) };
66 Self(ret)
67 }
68
69 fn sqrt(&self, rnd: RoundingMode) -> Self {
70 rnd.set();
71 let ret = unsafe { softfloat_sys_riscv::f16_sqrt(self.0) };
72 Self(ret)
73 }
74
75 fn compare<T: Borrow<Self>>(&self, x: T) -> Option<Ordering> {
76 let eq = unsafe { softfloat_sys_riscv::f16_eq(self.0, x.borrow().0) };
77 let lt = unsafe { softfloat_sys_riscv::f16_lt(self.0, x.borrow().0) };
78 if self.is_nan() || x.borrow().is_nan() {
79 None
80 } else if eq {
81 Some(Ordering::Equal)
82 } else if lt {
83 Some(Ordering::Less)
84 } else {
85 Some(Ordering::Greater)
86 }
87 }
88
89 fn from_u32(x: u32, rnd: RoundingMode) -> Self {
90 rnd.set();
91 let ret = unsafe { softfloat_sys_riscv::ui32_to_f16(x) };
92 Self(ret)
93 }
94
95 fn from_u64(x: u64, rnd: RoundingMode) -> Self {
96 rnd.set();
97 let ret = unsafe { softfloat_sys_riscv::ui64_to_f16(x) };
98 Self(ret)
99 }
100
101 fn from_i32(x: i32, rnd: RoundingMode) -> Self {
102 rnd.set();
103 let ret = unsafe { softfloat_sys_riscv::i32_to_f16(x) };
104 Self(ret)
105 }
106
107 fn from_i64(x: i64, rnd: RoundingMode) -> Self {
108 rnd.set();
109 let ret = unsafe { softfloat_sys_riscv::i64_to_f16(x) };
110 Self(ret)
111 }
112
113 fn to_u32(&self, rnd: RoundingMode) -> u32 {
114 let ret = unsafe { softfloat_sys_riscv::f16_to_ui32(self.0, rnd.to_softfloat(), false) };
115 ret as u32
116 }
117
118 fn to_u64(&self, rnd: RoundingMode) -> u64 {
119 let ret = unsafe { softfloat_sys_riscv::f16_to_ui64(self.0, rnd.to_softfloat(), false) };
120 ret
121 }
122
123 fn to_i32(&self, rnd: RoundingMode) -> i32 {
124 let ret = unsafe { softfloat_sys_riscv::f16_to_i32(self.0, rnd.to_softfloat(), false) };
125 ret as i32
126 }
127
128 fn to_i64(&self, rnd: RoundingMode) -> i64 {
129 let ret = unsafe { softfloat_sys_riscv::f16_to_i64(self.0, rnd.to_softfloat(), false) };
130 ret
131 }
132
133 fn to_f16(&self, _rnd: RoundingMode) -> F16 {
134 Self::from_bits(self.bits())
135 }
136
137 fn to_f32(&self, rnd: RoundingMode) -> F32 {
138 rnd.set();
139 let ret = unsafe { softfloat_sys_riscv::f16_to_f32(self.0) };
140 F32::from_bits(ret.v)
141 }
142
143 fn to_f64(&self, rnd: RoundingMode) -> F64 {
144 rnd.set();
145 let ret = unsafe { softfloat_sys_riscv::f16_to_f64(self.0) };
146 F64::from_bits(ret.v)
147 }
148
149 fn to_f128(&self, rnd: RoundingMode) -> F128 {
150 rnd.set();
151 let ret = unsafe { softfloat_sys_riscv::f16_to_f128(self.0) };
152 let mut v = 0u128;
153 v |= ret.v[0] as u128;
154 v |= (ret.v[1] as u128) << 64;
155 F128::from_bits(v)
156 }
157
158 fn round_to_integral(&self, rnd: RoundingMode) -> Self {
159 let ret = unsafe { softfloat_sys_riscv::f16_roundToInt(self.0, rnd.to_softfloat(), false) };
160 Self(ret)
161 }
162}
163
164#[cfg(test)]
165mod tests {
166 use super::*;
167
168 #[test]
169 fn f16_add() {
170 let a = 0x1234;
171 let b = 0x7654;
172 let a0 = F16::from_bits(a);
173 let b0 = F16::from_bits(b);
174 let d0 = a0.add(b0, RoundingMode::TiesToEven);
175 let a1 = simple_soft_float::F16::from_bits(a);
176 let b1 = simple_soft_float::F16::from_bits(b);
177 let d1 = a1.add(&b1, Some(simple_soft_float::RoundingMode::TiesToEven), None);
178 assert_eq!(d0.bits(), *d1.bits());
179 }
180
181 #[test]
182 fn f16_sub() {
183 let a = 0x1234;
184 let b = 0x7654;
185 let a0 = F16::from_bits(a);
186 let b0 = F16::from_bits(b);
187 let d0 = a0.sub(b0, RoundingMode::TiesToEven);
188 let a1 = simple_soft_float::F16::from_bits(a);
189 let b1 = simple_soft_float::F16::from_bits(b);
190 let d1 = a1.sub(&b1, Some(simple_soft_float::RoundingMode::TiesToEven), None);
191 assert_eq!(d0.bits(), *d1.bits());
192 }
193
194 #[test]
195 fn f16_mul() {
196 let a = 0x1234;
197 let b = 0x7654;
198 let a0 = F16::from_bits(a);
199 let b0 = F16::from_bits(b);
200 let d0 = a0.mul(b0, RoundingMode::TiesToEven);
201 let a1 = simple_soft_float::F16::from_bits(a);
202 let b1 = simple_soft_float::F16::from_bits(b);
203 let d1 = a1.mul(&b1, Some(simple_soft_float::RoundingMode::TiesToEven), None);
204 assert_eq!(d0.bits(), *d1.bits());
205 }
206
207 #[test]
208 fn f16_fused_mul_add() {
209 let a = 0x1234;
210 let b = 0x1234;
211 let c = 0x1234;
212 let a0 = F16::from_bits(a);
213 let b0 = F16::from_bits(b);
214 let c0 = F16::from_bits(c);
215 let d0 = a0.fused_mul_add(b0, c0, RoundingMode::TiesToEven);
216 let a1 = simple_soft_float::F16::from_bits(a);
217 let b1 = simple_soft_float::F16::from_bits(b);
218 let c1 = simple_soft_float::F16::from_bits(c);
219 let d1 = a1.fused_mul_add(
220 &b1,
221 &c1,
222 Some(simple_soft_float::RoundingMode::TiesToEven),
223 None,
224 );
225 assert_eq!(d0.bits(), *d1.bits());
226 }
227
228 #[test]
229 fn f16_div() {
230 let a = 0x7654;
231 let b = 0x1234;
232 let a0 = F16::from_bits(a);
233 let b0 = F16::from_bits(b);
234 let d0 = a0.div(b0, RoundingMode::TiesToEven);
235 let a1 = simple_soft_float::F16::from_bits(a);
236 let b1 = simple_soft_float::F16::from_bits(b);
237 let d1 = a1.div(&b1, Some(simple_soft_float::RoundingMode::TiesToEven), None);
238 assert_eq!(d0.bits(), *d1.bits());
239 }
240
241 #[test]
242 fn f16_rem() {
243 let a = 0x7654;
244 let b = 0x1234;
245 let a0 = F16::from_bits(a);
246 let b0 = F16::from_bits(b);
247 let d0 = a0.rem(b0, RoundingMode::TiesToEven);
248 let a1 = simple_soft_float::F16::from_bits(a);
249 let b1 = simple_soft_float::F16::from_bits(b);
250 let d1 = a1.ieee754_remainder(&b1, Some(simple_soft_float::RoundingMode::TiesToEven), None);
251 assert_eq!(d0.bits(), *d1.bits());
252 }
253
254 #[test]
255 fn f16_sqrt() {
256 let a = 0x7654;
257 let a0 = F16::from_bits(a);
258 let d0 = a0.sqrt(RoundingMode::TiesToEven);
259 let a1 = simple_soft_float::F16::from_bits(a);
260 let d1 = a1.sqrt(Some(simple_soft_float::RoundingMode::TiesToEven), None);
261 assert_eq!(d0.bits(), *d1.bits());
262 }
263
264 #[test]
265 fn f16_compare() {
266 let a = F16::from_bits(0x7654);
267 let b = F16::from_bits(0x1234);
268 let d = a.compare(b);
269 assert_eq!(d, Some(Ordering::Greater));
270
271 let a = F16::from_bits(0x1234);
272 let b = F16::from_bits(0x7654);
273 let d = a.compare(b);
274 assert_eq!(d, Some(Ordering::Less));
275
276 let a = F16::from_bits(0x1234);
277 let b = F16::from_bits(0x1234);
278 let d = a.compare(b);
279 assert_eq!(d, Some(Ordering::Equal));
280 }
281}