OpenCores
URL https://opencores.org/ocsvn/neorv32/neorv32/trunk

Subversion Repositories neorv32

[/] [neorv32/] [trunk/] [sw/] [example/] [floating_point_test/] [neorv32_zfinx_extension_intrinsics.h] - Blame information for rev 66

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 55 zero_gravi
// #################################################################################################
2
// # << NEORV32 - Intrinsics + Emulation Functions for the RISC-V "Zfinx" CPU extension >>         #
3
// # ********************************************************************************************* #
4
// # The intrinsics provided by this library allow to use the hardware floating-point unit of the  #
5
// # RISC-V Zfinx CPU extension without the need for Zfinx support by the compiler / toolchain.    #
6
// # ********************************************************************************************* #
7
// # BSD 3-Clause License                                                                          #
8
// #                                                                                               #
9
// # Copyright (c) 2021, Stephan Nolting. All rights reserved.                                     #
10
// #                                                                                               #
11
// # Redistribution and use in source and binary forms, with or without modification, are          #
12
// # permitted provided that the following conditions are met:                                     #
13
// #                                                                                               #
14
// # 1. Redistributions of source code must retain the above copyright notice, this list of        #
15
// #    conditions and the following disclaimer.                                                   #
16
// #                                                                                               #
17
// # 2. Redistributions in binary form must reproduce the above copyright notice, this list of     #
18
// #    conditions and the following disclaimer in the documentation and/or other materials        #
19
// #    provided with the distribution.                                                            #
20
// #                                                                                               #
21
// # 3. Neither the name of the copyright holder nor the names of its contributors may be used to  #
22
// #    endorse or promote products derived from this software without specific prior written      #
23
// #    permission.                                                                                #
24
// #                                                                                               #
25
// # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS   #
26
// # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF               #
27
// # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE    #
28
// # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,     #
29
// # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE #
30
// # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED    #
31
// # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING     #
32
// # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED  #
33
// # OF THE POSSIBILITY OF SUCH DAMAGE.                                                            #
34
// # ********************************************************************************************* #
35
// # The NEORV32 Processor - https://github.com/stnolting/neorv32              (c) Stephan Nolting #
36
// #################################################################################################
37
 
38
 
39
/**********************************************************************//**
40
 * @file floating_point_test/neorv32_zfinx_extension_intrinsics.h
41
 * @author Stephan Nolting
42
 *
43
 * @brief "Intrinsic" library for the NEORV32 single-precision floating-point in x registers (Zfinx) extension
44
 * @brief Also provides emulation functions for all intrinsics (functionality re-built in pure software). The functionality of the emulation
45
 * @brief functions is based on the RISC-V floating-point spec.
46
 *
47
 * @note All operations from this library use the default GCC "round to nearest, ties to even" rounding mode.
48
 *
49
 * @warning This library is just a temporary fall-back until the Zfinx extensions are supported by the upstream RISC-V GCC port.
50
 **************************************************************************/
51
 
52
#ifndef neorv32_zfinx_extension_intrinsics_h
53
#define neorv32_zfinx_extension_intrinsics_h
54
 
55
#define __USE_GNU
56
 
57
#include <fenv.h>
58
//#pragma STDC FENV_ACCESS ON
59
 
60
#define _GNU_SOURCE
61
 
62
#include <float.h>
63
#include <math.h>
64
 
65
 
66
/**********************************************************************//**
67
 * Sanity check
68
 **************************************************************************/
69
#if defined __riscv_f || (__riscv_flen == 32)
70
  #error Application programs using the Zfinx intrinsic library have to be compiled WITHOUT the <F> MARCH ISA attribute!
71
#endif
72
 
73
 
74
/**********************************************************************//**
75
 * Custom data type to access floating-point values as native floats and in binary representation
76
 **************************************************************************/
77
typedef union
78
{
79
  uint32_t binary_value; /**< Access as native float */
80
  float    float_value;  /**< Access in binary representation */
81
} float_conv_t;
82
 
83
 
84
// ################################################################################################
85
// Helper functions
86
// ################################################################################################
87
 
88
/**********************************************************************//**
89
 * Flush to zero if denormal number.
90
 *
91
 * @warning Subnormal numbers are not supported yet! Flush them to zero.
92
 *
93 56 zero_gravi
 * @param[in] tmp Source operand.
94 55 zero_gravi
 * @return Result.
95
 **************************************************************************/
96
float subnormal_flush(float tmp) {
97
 
98
  float res = tmp;
99
 
100
  if (fpclassify(tmp) == FP_SUBNORMAL) {
101
    if (signbit(tmp) != 0) {
102
      res = -0.0f;
103
    }
104
    else {
105
      res = +0.0f;
106
    }
107
  }
108
 
109
  return res;
110
}
111
 
112
 
113
// ################################################################################################
114
// Exception access
115
// ################################################################################################
116
 
117
/**********************************************************************//**
118
 * Get exception flags from fflags CSR (floating-point hardware).
119
 *
120
 * @return Floating point exception status word.
121
 **************************************************************************/
122
uint32_t get_hw_exceptions(void) {
123
 
124
  uint32_t res = neorv32_cpu_csr_read(CSR_FFLAGS);
125
 
126
  neorv32_cpu_csr_write(CSR_FFLAGS, 0); // clear status word
127
 
128
  return res;
129
}
130
 
131
 
132
/**********************************************************************//**
133
 * Get exception flags from C runtime (floating-point emulation).
134
 *
135
 * @warning WORK-IN-PROGRESS!
136
 *
137
 * @return Floating point exception status word.
138
 **************************************************************************/
139
uint32_t get_sw_exceptions(void) {
140
 
141
  const uint32_t FP_EXC_NV_C = 1 << 0; // invalid operation
142
  const uint32_t FP_EXC_DZ_C = 1 << 1; // divide by zero
143
  const uint32_t FP_EXC_OF_C = 1 << 2; // overflow
144
  const uint32_t FP_EXC_UF_C = 1 << 3; // underflow
145
  const uint32_t FP_EXC_NX_C = 1 << 4; // inexact
146
 
147
  int fpeRaised = fetestexcept(FE_ALL_EXCEPT);
148
 
149
  uint32_t res = 0;
150
 
151
  if (fpeRaised & FE_INVALID)   { res |= FP_EXC_NV_C; }
152
  if (fpeRaised & FE_DIVBYZERO) { res |= FP_EXC_DZ_C; }
153
  if (fpeRaised & FE_OVERFLOW)  { res |= FP_EXC_OF_C; }
154
  if (fpeRaised & FE_UNDERFLOW) { res |= FP_EXC_UF_C; }
155
  if (fpeRaised & FE_INEXACT)   { res |= FP_EXC_NX_C; }
156
 
157
  feclearexcept(FE_ALL_EXCEPT);
158
 
159
  return res;
160
}
161
 
162
 
163
// ################################################################################################
164
// "Intrinsics"
165
// ################################################################################################
166
 
167
/**********************************************************************//**
168
 * Single-precision floating-point addition
169
 *
170
 * @param[in] rs1 Source operand 1 (a0).
171
 * @param[in] rs2 Source operand 2 (a1).
172
 * @return Result.
173
 **************************************************************************/
174 56 zero_gravi
inline float __attribute__ ((always_inline)) riscv_intrinsic_fadds(float rs1, float rs2) {
175 55 zero_gravi
 
176
  float_conv_t opa, opb, res;
177
  opa.float_value = rs1;
178
  opb.float_value = rs2;
179
 
180
  register uint32_t result __asm__ ("a0");
181
  register uint32_t tmp_a  __asm__ ("a0") = opa.binary_value;
182
  register uint32_t tmp_b  __asm__ ("a1") = opb.binary_value;
183
 
184
  // dummy instruction to prevent GCC "constprop" optimization
185 63 zero_gravi
  asm volatile ("" : [output] "=r" (result) : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b));
186 55 zero_gravi
 
187
  // fadd.s a0, a0, a1
188
  CUSTOM_INSTR_R2_TYPE(0b0000000, a1, a0, 0b000, a0, 0b1010011);
189
 
190
  res.binary_value = result;
191
  return res.float_value;
192
}
193
 
194
 
195
/**********************************************************************//**
196
 * Single-precision floating-point subtraction
197
 *
198
 * @param[in] rs1 Source operand 1 (a0).
199
 * @param[in] rs2 Source operand 2 (a1).
200
 * @return Result.
201
 **************************************************************************/
202 56 zero_gravi
inline float __attribute__ ((always_inline)) riscv_intrinsic_fsubs(float rs1, float rs2) {
203 55 zero_gravi
 
204
  float_conv_t opa, opb, res;
205
  opa.float_value = rs1;
206
  opb.float_value = rs2;
207
 
208
  register uint32_t result __asm__ ("a0");
209
  register uint32_t tmp_a  __asm__ ("a0") = opa.binary_value;
210
  register uint32_t tmp_b  __asm__ ("a1") = opb.binary_value;
211
 
212
  // dummy instruction to prevent GCC "constprop" optimization
213 63 zero_gravi
  asm volatile ("" : [output] "=r" (result) : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b));
214 55 zero_gravi
 
215
  // fsub.s a0, a0, a1
216
  CUSTOM_INSTR_R2_TYPE(0b0000100, a1, a0, 0b000, a0, 0b1010011);
217
 
218
  res.binary_value = result;
219
  return res.float_value;
220
}
221
 
222
 
223
/**********************************************************************//**
224
 * Single-precision floating-point multiplication
225
 *
226
 * @param[in] rs1 Source operand 1 (a0).
227
 * @param[in] rs2 Source operand 2 (a1).
228
 * @return Result.
229
 **************************************************************************/
230 56 zero_gravi
inline float __attribute__ ((always_inline)) riscv_intrinsic_fmuls(float rs1, float rs2) {
231 55 zero_gravi
 
232
  float_conv_t opa, opb, res;
233
  opa.float_value = rs1;
234
  opb.float_value = rs2;
235
 
236
  register uint32_t result __asm__ ("a0");
237
  register uint32_t tmp_a  __asm__ ("a0") = opa.binary_value;
238
  register uint32_t tmp_b  __asm__ ("a1") = opb.binary_value;
239
 
240
  // dummy instruction to prevent GCC "constprop" optimization
241 63 zero_gravi
  asm volatile ("" : [output] "=r" (result) : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b));
242 55 zero_gravi
 
243
  // fmul.s a0, a0, a1
244
  CUSTOM_INSTR_R2_TYPE(0b0001000, a1, a0, 0b000, a0, 0b1010011);
245
 
246
  res.binary_value = result;
247
  return res.float_value;
248
}
249
 
250
 
251
/**********************************************************************//**
252
 * Single-precision floating-point minimum
253
 *
254
 * @param[in] rs1 Source operand 1 (a0).
255
 * @param[in] rs2 Source operand 2 (a1).
256
 * @return Result.
257
 **************************************************************************/
258 56 zero_gravi
inline float __attribute__ ((always_inline)) riscv_intrinsic_fmins(float rs1, float rs2) {
259 55 zero_gravi
 
260
  float_conv_t opa, opb, res;
261
  opa.float_value = rs1;
262
  opb.float_value = rs2;
263
 
264
  register uint32_t result __asm__ ("a0");
265
  register uint32_t tmp_a  __asm__ ("a0") = opa.binary_value;
266
  register uint32_t tmp_b  __asm__ ("a1") = opb.binary_value;
267
 
268
  // dummy instruction to prevent GCC "constprop" optimization
269 63 zero_gravi
  asm volatile ("" : [output] "=r" (result) : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b));
270 55 zero_gravi
 
271
  // fmin.s a0, a0, a1
272
  CUSTOM_INSTR_R2_TYPE(0b0010100, a1, a0, 0b000, a0, 0b1010011);
273
 
274
  res.binary_value = result;
275
  return res.float_value;
276
}
277
 
278
 
279
/**********************************************************************//**
280
 * Single-precision floating-point maximum
281
 *
282
 * @param[in] rs1 Source operand 1 (a0).
283
 * @param[in] rs2 Source operand 2 (a1).
284
 * @return Result.
285
 **************************************************************************/
286 56 zero_gravi
inline float __attribute__ ((always_inline)) riscv_intrinsic_fmaxs(float rs1, float rs2) {
287 55 zero_gravi
 
288
  float_conv_t opa, opb, res;
289
  opa.float_value = rs1;
290
  opb.float_value = rs2;
291
 
292
  register uint32_t result __asm__ ("a0");
293
  register uint32_t tmp_a  __asm__ ("a0") = opa.binary_value;
294
  register uint32_t tmp_b  __asm__ ("a1") = opb.binary_value;
295
 
296
  // dummy instruction to prevent GCC "constprop" optimization
297 63 zero_gravi
  asm volatile ("" : [output] "=r" (result) : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b));
298 55 zero_gravi
 
299
  // fmax.s a0, a0, a1
300
  CUSTOM_INSTR_R2_TYPE(0b0010100, a1, a0, 0b001, a0, 0b1010011);
301
 
302
  res.binary_value = result;
303
  return res.float_value;
304
}
305
 
306
 
307
/**********************************************************************//**
308
 * Single-precision floating-point convert float to unsigned integer
309
 *
310
 * @param[in] rs1 Source operand 1 (a0).
311
 * @return Result.
312
 **************************************************************************/
313 56 zero_gravi
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_fcvt_wus(float rs1) {
314 55 zero_gravi
 
315
  float_conv_t opa;
316
  opa.float_value = rs1;
317
 
318
  register uint32_t result __asm__ ("a0");
319
  register uint32_t tmp_a  __asm__ ("a0") = opa.binary_value;
320
 
321
  // dummy instruction to prevent GCC "constprop" optimization
322 63 zero_gravi
  asm volatile ("" : [output] "=r" (result) : [input_i] "r" (tmp_a));
323 55 zero_gravi
 
324
  // fcvt.wu.s a0, a0
325
  CUSTOM_INSTR_R2_TYPE(0b1100000, x1, a0, 0b000, a0, 0b1010011);
326
 
327
  return result;
328
}
329
 
330
 
331
/**********************************************************************//**
332
 * Single-precision floating-point convert float to signed integer
333
 *
334
 * @param[in] rs1 Source operand 1 (a0).
335
 * @return Result.
336
 **************************************************************************/
337 56 zero_gravi
inline int32_t __attribute__ ((always_inline)) riscv_intrinsic_fcvt_ws(float rs1) {
338 55 zero_gravi
 
339
  float_conv_t opa;
340
  opa.float_value = rs1;
341
 
342
  register uint32_t result __asm__ ("a0");
343
  register uint32_t tmp_a  __asm__ ("a0") = opa.binary_value;
344
 
345
  // dummy instruction to prevent GCC "constprop" optimization
346 63 zero_gravi
  asm volatile ("" : [output] "=r" (result) : [input_i] "r" (tmp_a));
347 55 zero_gravi
 
348
  // fcvt.w.s a0, a0
349
  CUSTOM_INSTR_R2_TYPE(0b1100000, x0, a0, 0b000, a0, 0b1010011);
350
 
351
  return (int32_t)result;
352
}
353
 
354
 
355
/**********************************************************************//**
356
 * Single-precision floating-point convert unsigned integer to float
357
 *
358
 * @param[in] rs1 Source operand 1 (a0).
359
 * @return Result.
360
 **************************************************************************/
361 56 zero_gravi
inline float __attribute__ ((always_inline)) riscv_intrinsic_fcvt_swu(uint32_t rs1) {
362 55 zero_gravi
 
363
  float_conv_t res;
364
 
365
  register uint32_t result __asm__ ("a0");
366
  register uint32_t tmp_a  __asm__ ("a0") = rs1;
367
 
368
  // dummy instruction to prevent GCC "constprop" optimization
369 63 zero_gravi
  asm volatile ("" : [output] "=r" (result) : [input_i] "r" (tmp_a));
370 55 zero_gravi
 
371
  // fcvt.s.wu a0, a0
372
  CUSTOM_INSTR_R2_TYPE(0b1101000, x1, a0, 0b000, a0, 0b1010011);
373
 
374
  res.binary_value = result;
375
  return res.float_value;
376
}
377
 
378
 
379
/**********************************************************************//**
380
 * Single-precision floating-point convert signed integer to float
381
 *
382
 * @param[in] rs1 Source operand 1 (a0).
383
 * @return Result.
384
 **************************************************************************/
385 56 zero_gravi
inline float __attribute__ ((always_inline)) riscv_intrinsic_fcvt_sw(int32_t rs1) {
386 55 zero_gravi
 
387
  float_conv_t res;
388
 
389
  register uint32_t result __asm__ ("a0");
390
  register uint32_t tmp_a  __asm__ ("a0") = (uint32_t)rs1;
391
 
392
  // dummy instruction to prevent GCC "constprop" optimization
393 63 zero_gravi
  asm volatile ("" : [output] "=r" (result) : [input_i] "r" (tmp_a));
394 55 zero_gravi
 
395
  // fcvt.s.w a0, a0
396
  CUSTOM_INSTR_R2_TYPE(0b1101000, x0, a0, 0b000, a0, 0b1010011);
397
 
398
  res.binary_value = result;
399
  return res.float_value;
400
}
401
 
402
 
403
/**********************************************************************//**
404
 * Single-precision floating-point equal comparison
405
 *
406
 * @param[in] rs1 Source operand 1 (a0).
407
 * @param[in] rs2 Source operand 2 (a1).
408
 * @return Result.
409
 **************************************************************************/
410 56 zero_gravi
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_feqs(float rs1, float rs2) {
411 55 zero_gravi
 
412
  float_conv_t opa, opb;
413
  opa.float_value = rs1;
414
  opb.float_value = rs2;
415
 
416
  register uint32_t result __asm__ ("a0");
417
  register uint32_t tmp_a  __asm__ ("a0") = opa.binary_value;
418
  register uint32_t tmp_b  __asm__ ("a1") = opb.binary_value;
419
 
420
  // dummy instruction to prevent GCC "constprop" optimization
421 63 zero_gravi
  asm volatile ("" : [output] "=r" (result) : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b));
422 55 zero_gravi
 
423
  // feq.s a0, a0, a1
424
  CUSTOM_INSTR_R2_TYPE(0b1010000, a1, a0, 0b010, a0, 0b1010011);
425
 
426
  return result;
427
}
428
 
429
 
430
/**********************************************************************//**
431
 * Single-precision floating-point less-than comparison
432
 *
433
 * @param[in] rs1 Source operand 1 (a0).
434
 * @param[in] rs2 Source operand 2 (a1).
435
 * @return Result.
436
 **************************************************************************/
437 56 zero_gravi
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_flts(float rs1, float rs2) {
438 55 zero_gravi
 
439
  float_conv_t opa, opb;
440
  opa.float_value = rs1;
441
  opb.float_value = rs2;
442
 
443
  register uint32_t result __asm__ ("a0");
444
  register uint32_t tmp_a  __asm__ ("a0") = opa.binary_value;
445
  register uint32_t tmp_b  __asm__ ("a1") = opb.binary_value;
446
 
447
  // dummy instruction to prevent GCC "constprop" optimization
448 63 zero_gravi
  asm volatile ("" : [output] "=r" (result) : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b));
449 55 zero_gravi
 
450
  // flt.s a0, a0, a1
451
  CUSTOM_INSTR_R2_TYPE(0b1010000, a1, a0, 0b001, a0, 0b1010011);
452
 
453
  return result;
454
}
455
 
456
 
457
/**********************************************************************//**
458
 * Single-precision floating-point less-than-or-equal comparison
459
 *
460
 * @param[in] rs1 Source operand 1 (a0).
461
 * @param[in] rs2 Source operand 2 (a1).
462
 * @return Result.
463
 **************************************************************************/
464 56 zero_gravi
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_fles(float rs1, float rs2) {
465 55 zero_gravi
 
466
  float_conv_t opa, opb;
467
  opa.float_value = rs1;
468
  opb.float_value = rs2;
469
 
470
  register uint32_t result __asm__ ("a0");
471
  register uint32_t tmp_a  __asm__ ("a0") = opa.binary_value;
472
  register uint32_t tmp_b  __asm__ ("a1") = opb.binary_value;
473
 
474
  // dummy instruction to prevent GCC "constprop" optimization
475 63 zero_gravi
  asm volatile ("" : [output] "=r" (result) : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b));
476 55 zero_gravi
 
477
  // fle.s a0, a0, a1
478
  CUSTOM_INSTR_R2_TYPE(0b1010000, a1, a0, 0b000, a0, 0b1010011);
479
 
480
  return result;
481
}
482
 
483
 
484
/**********************************************************************//**
485
 * Single-precision floating-point sign-injection
486
 *
487
 * @param[in] rs1 Source operand 1 (a0).
488
 * @param[in] rs2 Source operand 2 (a1).
489
 * @return Result.
490
 **************************************************************************/
491 56 zero_gravi
inline float __attribute__ ((always_inline)) riscv_intrinsic_fsgnjs(float rs1, float rs2) {
492 55 zero_gravi
 
493
  float_conv_t opa, opb, res;
494
  opa.float_value = rs1;
495
  opb.float_value = rs2;
496
 
497
  register uint32_t result __asm__ ("a0");
498
  register uint32_t tmp_a  __asm__ ("a0") = opa.binary_value;
499
  register uint32_t tmp_b  __asm__ ("a1") = opb.binary_value;
500
 
501
  // dummy instruction to prevent GCC "constprop" optimization
502 63 zero_gravi
  asm volatile ("" : [output] "=r" (result) : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b));
503 55 zero_gravi
 
504
  // fsgnj.s a0, a0, a1
505
  CUSTOM_INSTR_R2_TYPE(0b0010000, a1, a0, 0b000, a0, 0b1010011);
506
 
507
  res.binary_value = result;
508
  return res.float_value;
509
}
510
 
511
 
512
/**********************************************************************//**
513
 * Single-precision floating-point sign-injection NOT
514
 *
515
 * @param[in] rs1 Source operand 1 (a0).
516
 * @param[in] rs2 Source operand 2 (a1).
517
 * @return Result.
518
 **************************************************************************/
519 56 zero_gravi
inline float __attribute__ ((always_inline)) riscv_intrinsic_fsgnjns(float rs1, float rs2) {
520 55 zero_gravi
 
521
  float_conv_t opa, opb, res;
522
  opa.float_value = rs1;
523
  opb.float_value = rs2;
524
 
525
  register uint32_t result __asm__ ("a0");
526
  register uint32_t tmp_a  __asm__ ("a0") = opa.binary_value;
527
  register uint32_t tmp_b  __asm__ ("a1") = opb.binary_value;
528
 
529
  // dummy instruction to prevent GCC "constprop" optimization
530 63 zero_gravi
  asm volatile ("" : [output] "=r" (result) : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b));
531 55 zero_gravi
 
532
  // fsgnjn.s a0, a0, a1
533
  CUSTOM_INSTR_R2_TYPE(0b0010000, a1, a0, 0b001, a0, 0b1010011);
534
 
535
  res.binary_value = result;
536
  return res.float_value;
537
}
538
 
539
 
540
/**********************************************************************//**
541
 * Single-precision floating-point sign-injection XOR
542
 *
543
 * @param[in] rs1 Source operand 1 (a0).
544
 * @param[in] rs2 Source operand 2 (a1).
545
 * @return Result.
546
 **************************************************************************/
547 56 zero_gravi
inline float __attribute__ ((always_inline)) riscv_intrinsic_fsgnjxs(float rs1, float rs2) {
548 55 zero_gravi
 
549
  float_conv_t opa, opb, res;
550
  opa.float_value = rs1;
551
  opb.float_value = rs2;
552
 
553
  register uint32_t result __asm__ ("a0");
554
  register uint32_t tmp_a  __asm__ ("a0") = opa.binary_value;
555
  register uint32_t tmp_b  __asm__ ("a1") = opb.binary_value;
556
 
557
  // dummy instruction to prevent GCC "constprop" optimization
558 63 zero_gravi
  asm volatile ("" : [output] "=r" (result) : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b));
559 55 zero_gravi
 
560
  // fsgnjx.s a0, a0, a1
561
  CUSTOM_INSTR_R2_TYPE(0b0010000, a1, a0, 0b010, a0, 0b1010011);
562
 
563
  res.binary_value = result;
564
  return res.float_value;
565
}
566
 
567
 
568
/**********************************************************************//**
569
 * Single-precision floating-point number classification
570
 *
571
 * @param[in] rs1 Source operand 1 (a0).
572
 * @return Result.
573
 **************************************************************************/
574 56 zero_gravi
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_fclasss(float rs1) {
575 55 zero_gravi
 
576
  float_conv_t opa;
577
  opa.float_value = rs1;
578
 
579
  register uint32_t result __asm__ ("a0");
580
  register uint32_t tmp_a  __asm__ ("a0") = opa.binary_value;
581
 
582
  // dummy instruction to prevent GCC "constprop" optimization
583 63 zero_gravi
  asm volatile ("" : [output] "=r" (result) : [input_i] "r" (tmp_a));
584 55 zero_gravi
 
585
  // fclass.s a0, a0
586
  CUSTOM_INSTR_R2_TYPE(0b1110000, x0, a0, 0b001, a0, 0b1010011);
587
 
588
  return result;
589
}
590
 
591
 
592
// ################################################################################################
593
// !!! UNSUPPORTED instructions !!!
594
// ################################################################################################
595
 
596
/**********************************************************************//**
597
 * Single-precision floating-point division
598
 *
599
 * @warning This instruction is not supported and should raise an illegal instruction exception when executed.
600
 *
601
 * @param[in] rs1 Source operand 1 (a0).
602
 * @param[in] rs2 Source operand 2 (a1).
603
 * @return Result.
604
 **************************************************************************/
605 56 zero_gravi
inline float __attribute__ ((always_inline)) riscv_intrinsic_fdivs(float rs1, float rs2) {
606 55 zero_gravi
 
607
  float_conv_t opa, opb, res;
608
  opa.float_value = rs1;
609
  opb.float_value = rs2;
610
 
611
  register uint32_t result __asm__ ("a0");
612
  register uint32_t tmp_a  __asm__ ("a0") = opa.binary_value;
613
  register uint32_t tmp_b  __asm__ ("a1") = opb.binary_value;
614
 
615
  // dummy instruction to prevent GCC "constprop" optimization
616
  asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b));
617
 
618
  // fdiv.s a0, a0, x1
619
  CUSTOM_INSTR_R2_TYPE(0b0001100, a1, a0, 0b000, a0, 0b1010011);
620
 
621 56 zero_gravi
  // dummy instruction to prevent GCC "constprop" optimization
622
  asm volatile ("add %[res], %[input], x0" : [res] "=r" (result) : [input] "r" (result) );
623
 
624 55 zero_gravi
  res.binary_value = result;
625
  return res.float_value;
626
}
627
 
628
 
629
/**********************************************************************//**
630
 * Single-precision floating-point square root
631
 *
632
 * @warning This instruction is not supported and should raise an illegal instruction exception when executed.
633
 *
634
 * @param[in] rs1 Source operand 1 (a0).
635
 * @return Result.
636
 **************************************************************************/
637 56 zero_gravi
inline float __attribute__ ((always_inline)) riscv_intrinsic_fsqrts(float rs1) {
638 55 zero_gravi
 
639
  float_conv_t opa, res;
640
  opa.float_value = rs1;
641
 
642
  register uint32_t result __asm__ ("a0");
643
  register uint32_t tmp_a  __asm__ ("a0") = opa.binary_value;
644
 
645
  // dummy instruction to prevent GCC "constprop" optimization
646
  asm volatile ("add x0, %[input_i], x0" : : [input_i] "r" (tmp_a));
647
 
648
  // fsqrt.s a0, a0, a1
649
  CUSTOM_INSTR_R2_TYPE(0b0101100, a1, a0, 0b000, a0, 0b1010011);
650
 
651 56 zero_gravi
  // dummy instruction to prevent GCC "constprop" optimization
652
  asm volatile ("add %[res], %[input], x0" : [res] "=r" (result) : [input] "r" (result) );
653
 
654 55 zero_gravi
  res.binary_value = result;
655
  return res.float_value;
656
}
657
 
658
 
659
/**********************************************************************//**
660
 * Single-precision floating-point fused multiply-add
661
 *
662
 * @warning This instruction is not supported and should raise an illegal instruction exception when executed.
663
 *
664
 * @param[in] rs1 Source operand 1 (a0)
665
 * @param[in] rs2 Source operand 2 (a1)
666
 * @param[in] rs3 Source operand 3 (a2)
667
 * @return Result.
668
 **************************************************************************/
669 56 zero_gravi
inline float __attribute__ ((always_inline)) riscv_intrinsic_fmadds(float rs1, float rs2, float rs3) {
670 55 zero_gravi
 
671
  float_conv_t opa, opb, opc, res;
672
  opa.float_value = rs1;
673
  opb.float_value = rs2;
674
  opc.float_value = rs3;
675
 
676
  register uint32_t result __asm__ ("a0");
677
  register uint32_t tmp_a  __asm__ ("a0") = opa.binary_value;
678
  register uint32_t tmp_b  __asm__ ("a1") = opb.binary_value;
679
  register uint32_t tmp_c  __asm__ ("a2") = opc.binary_value;
680
 
681
  // dummy instruction to prevent GCC "constprop" optimization
682
  asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b));
683
  asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_b), [input_j] "r" (tmp_c));
684
 
685
  // fmadd.s a0, a0, a1, a2
686
  CUSTOM_INSTR_R3_TYPE(a2, a1, a0, 0b000, a0, 0b1000011);
687
 
688 56 zero_gravi
  // dummy instruction to prevent GCC "constprop" optimization
689
  asm volatile ("add %[res], %[input], x0" : [res] "=r" (result) : [input] "r" (result) );
690
 
691 55 zero_gravi
  res.binary_value = result;
692
  return res.float_value;
693
}
694
 
695
 
696
/**********************************************************************//**
697
 * Single-precision floating-point fused multiply-sub
698
 *
699
 * @warning This instruction is not supported and should raise an illegal instruction exception when executed.
700
 *
701
 * @param[in] rs1 Source operand 1 (a0)
702
 * @param[in] rs2 Source operand 2 (a1)
703
 * @param[in] rs3 Source operand 3 (a2)
704
 * @return Result.
705
 **************************************************************************/
706 56 zero_gravi
inline float __attribute__ ((always_inline)) riscv_intrinsic_fmsubs(float rs1, float rs2, float rs3) {
707 55 zero_gravi
 
708
  float_conv_t opa, opb, opc, res;
709
  opa.float_value = rs1;
710
  opb.float_value = rs2;
711
  opc.float_value = rs3;
712
 
713
  register uint32_t result __asm__ ("a0");
714
  register uint32_t tmp_a  __asm__ ("a0") = opa.binary_value;
715
  register uint32_t tmp_b  __asm__ ("a1") = opb.binary_value;
716
  register uint32_t tmp_c  __asm__ ("a2") = opc.binary_value;
717
 
718
  // dummy instruction to prevent GCC "constprop" optimization
719
  asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b));
720
  asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_b), [input_j] "r" (tmp_c));
721
 
722
  // fmsub.s a0, a0, a1, a2
723
  CUSTOM_INSTR_R3_TYPE(a2, a1, a0, 0b000, a0, 0b1000111);
724
 
725 56 zero_gravi
  // dummy instruction to prevent GCC "constprop" optimization
726
  asm volatile ("add %[res], %[input], x0" : [res] "=r" (result) : [input] "r" (result) );
727
 
728 55 zero_gravi
  res.binary_value = result;
729
  return res.float_value;
730
}
731
 
732
 
733
/**********************************************************************//**
734
 * Single-precision floating-point fused negated multiply-sub
735
 *
736
 * @warning This instruction is not supported and should raise an illegal instruction exception when executed.
737
 *
738
 * @param[in] rs1 Source operand 1 (a0)
739
 * @param[in] rs2 Source operand 2 (a1)
740
 * @param[in] rs3 Source operand 3 (a2)
741
 * @return Result.
742
 **************************************************************************/
743 56 zero_gravi
inline float __attribute__ ((always_inline)) riscv_intrinsic_fnmsubs(float rs1, float rs2, float rs3) {
744 55 zero_gravi
 
745
  float_conv_t opa, opb, opc, res;
746
  opa.float_value = rs1;
747
  opb.float_value = rs2;
748
  opc.float_value = rs3;
749
 
750
  register uint32_t result __asm__ ("a0");
751
  register uint32_t tmp_a  __asm__ ("a0") = opa.binary_value;
752
  register uint32_t tmp_b  __asm__ ("a1") = opb.binary_value;
753
  register uint32_t tmp_c  __asm__ ("a2") = opc.binary_value;
754
 
755
  // dummy instruction to prevent GCC "constprop" optimization
756
  asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b));
757
  asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_b), [input_j] "r" (tmp_c));
758
 
759
  // fnmsub.s a0, a0, a1, a2
760
  CUSTOM_INSTR_R3_TYPE(a2, a1, a0, 0b000, a0, 0b1001011);
761
 
762 56 zero_gravi
  // dummy instruction to prevent GCC "constprop" optimization
763
  asm volatile ("add %[res], %[input], x0" : [res] "=r" (result) : [input] "r" (result) );
764
 
765 55 zero_gravi
  res.binary_value = result;
766
  return res.float_value;
767
}
768
 
769
 
770
/**********************************************************************//**
771
 * Single-precision floating-point fused negated multiply-add
772
 *
773
 * @warning This instruction is not supported and should raise an illegal instruction exception when executed.
774
 *
775
 * @param[in] rs1 Source operand 1 (a0)
776
 * @param[in] rs2 Source operand 2 (a1)
777
 * @param[in] rs3 Source operand 3 (a2)
778
 * @return Result.
779
 **************************************************************************/
780 56 zero_gravi
inline float __attribute__ ((always_inline)) riscv_intrinsic_fnmadds(float rs1, float rs2, float rs3) {
781 55 zero_gravi
 
782
  float_conv_t opa, opb, opc, res;
783
  opa.float_value = rs1;
784
  opb.float_value = rs2;
785
  opc.float_value = rs3;
786
 
787
  register uint32_t result __asm__ ("a0");
788
  register uint32_t tmp_a  __asm__ ("a0") = opa.binary_value;
789
  register uint32_t tmp_b  __asm__ ("a1") = opb.binary_value;
790
  register uint32_t tmp_c  __asm__ ("a2") = opc.binary_value;
791
 
792
  // dummy instruction to prevent GCC "constprop" optimization
793
  asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b));
794
  asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_b), [input_j] "r" (tmp_c));
795
 
796
  // fnmadd.s a0, a0, a1, a2
797
  CUSTOM_INSTR_R3_TYPE(a2, a1, a0, 0b000, a0, 0b1001111);
798
 
799 56 zero_gravi
  // dummy instruction to prevent GCC "constprop" optimization
800
  asm volatile ("add %[res], %[input], x0" : [res] "=r" (result) : [input] "r" (result) );
801
 
802 55 zero_gravi
  res.binary_value = result;
803
  return res.float_value;
804
}
805
 
806
 
807
// ################################################################################################
808
// Emulation functions
809
// ################################################################################################
810
 
811
/**********************************************************************//**
812
 * Single-precision floating-point addition
813
 *
814
 * @param[in] rs1 Source operand 1.
815
 * @param[in] rs2 Source operand 2.
816
 * @return Result.
817
 **************************************************************************/
818 56 zero_gravi
float __attribute__ ((noinline)) riscv_emulate_fadds(float rs1, float rs2) {
819 55 zero_gravi
 
820
  float opa = subnormal_flush(rs1);
821
  float opb = subnormal_flush(rs2);
822
 
823
  float res = opa + opb;
824
  return subnormal_flush(res);
825
}
826
 
827
 
828
/**********************************************************************//**
829
 * Single-precision floating-point subtraction
830
 *
831
 * @param[in] rs1 Source operand 1.
832
 * @param[in] rs2 Source operand 2.
833
 * @return Result.
834
 **************************************************************************/
835 56 zero_gravi
float __attribute__ ((noinline)) riscv_emulate_fsubs(float rs1, float rs2) {
836 55 zero_gravi
 
837
  float opa = subnormal_flush(rs1);
838
  float opb = subnormal_flush(rs2);
839
 
840
  float res = opa - opb;
841
  return subnormal_flush(res);
842
}
843
 
844
 
845
/**********************************************************************//**
846
 * Single-precision floating-point multiplication
847
 *
848
 * @param[in] rs1 Source operand 1.
849
 * @param[in] rs2 Source operand 2.
850
 * @return Result.
851
 **************************************************************************/
852 56 zero_gravi
float __attribute__ ((noinline)) riscv_emulate_fmuls(float rs1, float rs2) {
853 55 zero_gravi
 
854
  float opa = subnormal_flush(rs1);
855
  float opb = subnormal_flush(rs2);
856
 
857
  float res = opa * opb;
858
  return subnormal_flush(res);
859
}
860
 
861
 
862
/**********************************************************************//**
863
 * Single-precision floating-point minimum
864
 *
865
 * @param[in] rs1 Source operand 1.
866
 * @param[in] rs2 Source operand 2.
867
 * @return Result.
868
 **************************************************************************/
869 56 zero_gravi
float __attribute__ ((noinline)) riscv_emulate_fmins(float rs1, float rs2) {
870 55 zero_gravi
 
871
  float opa = subnormal_flush(rs1);
872
  float opb = subnormal_flush(rs2);
873
 
874
  union {
875
  uint32_t binary_value; /**< Access as native float */
876
  float    float_value;  /**< Access in binary representation */
877
  } tmp_a, tmp_b;
878
 
879
  if ((fpclassify(opa) == FP_NAN) && (fpclassify(opb) == FP_NAN)) {
880
    return nanf("");
881
  }
882
 
883
  if (fpclassify(opa) == FP_NAN) {
884
    return opb;
885
  }
886
 
887
  if (fpclassify(opb) == FP_NAN) {
888
    return opa;
889
  }
890
 
891
  // RISC-V spec: -0 < +0
892
  tmp_a.float_value = opa;
893
  tmp_b.float_value = opb;
894
  if (((tmp_a.binary_value == 0x80000000) && (tmp_b.binary_value == 0x00000000)) ||
895
      ((tmp_a.binary_value == 0x00000000) && (tmp_b.binary_value == 0x80000000))) {
896
    return -0.0f;
897
  }
898
 
899
  return fmin(opa, opb);
900
}
901
 
902
 
903
/**********************************************************************//**
904
 * Single-precision floating-point maximum
905
 *
906
 * @param[in] rs1 Source operand 1.
907
 * @param[in] rs2 Source operand 2.
908
 * @return Result.
909
 **************************************************************************/
910 56 zero_gravi
float __attribute__ ((noinline)) riscv_emulate_fmaxs(float rs1, float rs2) {
911 55 zero_gravi
 
912
  float opa = subnormal_flush(rs1);
913
  float opb = subnormal_flush(rs2);
914
 
915
  union {
916
  uint32_t binary_value; /**< Access as native float */
917
  float    float_value;  /**< Access in binary representation */
918
  } tmp_a, tmp_b;
919
 
920
 
921
  if ((fpclassify(opa) == FP_NAN) && (fpclassify(opb) == FP_NAN)) {
922
    return nanf("");
923
  }
924
 
925
  if (fpclassify(opa) == FP_NAN) {
926
    return opb;
927
  }
928
 
929
  if (fpclassify(opb) == FP_NAN) {
930
    return opa;
931
  }
932
 
933
  // RISC-V spec: -0 < +0
934
  tmp_a.float_value = opa;
935
  tmp_b.float_value = opb;
936
  if (((tmp_a.binary_value == 0x80000000) && (tmp_b.binary_value == 0x00000000)) ||
937
      ((tmp_a.binary_value == 0x00000000) && (tmp_b.binary_value == 0x80000000))) {
938
    return +0.0f;
939
  }
940
 
941
  return fmax(opa, opb);
942
}
943
 
944
 
945
/**********************************************************************//**
946
 * Single-precision floating-point float to unsigned integer
947
 *
948
 * @param[in] rs1 Source operand 1.
949
 * @return Result.
950
 **************************************************************************/
951 56 zero_gravi
uint32_t __attribute__ ((noinline)) riscv_emulate_fcvt_wus(float rs1) {
952 55 zero_gravi
 
953
  float opa = subnormal_flush(rs1);
954
 
955
  return (uint32_t)roundf(opa);
956
}
957
 
958
 
959
/**********************************************************************//**
960
 * Single-precision floating-point float to signed integer
961
 *
962
 * @param[in] rs1 Source operand 1.
963
 * @return Result.
964
 **************************************************************************/
965 56 zero_gravi
int32_t __attribute__ ((noinline)) riscv_emulate_fcvt_ws(float rs1) {
966 55 zero_gravi
 
967
  float opa = subnormal_flush(rs1);
968
 
969
  return (int32_t)roundf(opa);
970
}
971
 
972
 
973
/**********************************************************************//**
974
 * Single-precision floating-point unsigned integer to float
975
 *
976
 * @param[in] rs1 Source operand 1.
977
 * @return Result.
978
 **************************************************************************/
979 56 zero_gravi
float __attribute__ ((noinline)) riscv_emulate_fcvt_swu(uint32_t rs1) {
980 55 zero_gravi
 
981
  return (float)rs1;
982
}
983
 
984
 
985
/**********************************************************************//**
986
 * Single-precision floating-point signed integer to float
987
 *
988
 * @param[in] rs1 Source operand 1.
989
 * @return Result.
990
 **************************************************************************/
991 56 zero_gravi
float __attribute__ ((noinline)) riscv_emulate_fcvt_sw(int32_t rs1) {
992 55 zero_gravi
 
993
  return (float)rs1;
994
}
995
 
996
 
997
/**********************************************************************//**
998
 * Single-precision floating-point equal comparison
999
 *
1000
 * @param[in] rs1 Source operand 1.
1001
 * @param[in] rs2 Source operand 2.
1002
 * @return Result.
1003
 **************************************************************************/
1004 56 zero_gravi
uint32_t __attribute__ ((noinline)) riscv_emulate_feqs(float rs1, float rs2) {
1005 55 zero_gravi
 
1006
  float opa = subnormal_flush(rs1);
1007
  float opb = subnormal_flush(rs2);
1008
 
1009
  if ((fpclassify(opa) == FP_NAN) || (fpclassify(opb) == FP_NAN)) {
1010
    return 0;
1011
  }
1012
 
1013
  if isless(opa, opb) {
1014
    return 0;
1015
  }
1016
  else if isgreater(opa, opb) {
1017
    return 0;
1018
  }
1019
  else {
1020
    return 1;
1021
  }
1022
}
1023
 
1024
 
1025
/**********************************************************************//**
1026
 * Single-precision floating-point less-than comparison
1027
 *
1028
 * @param[in] rs1 Source operand 1.
1029
 * @param[in] rs2 Source operand 2.
1030
 * @return Result.
1031
 **************************************************************************/
1032 56 zero_gravi
uint32_t __attribute__ ((noinline)) riscv_emulate_flts(float rs1, float rs2) {
1033 55 zero_gravi
 
1034
  float opa = subnormal_flush(rs1);
1035
  float opb = subnormal_flush(rs2);
1036
 
1037
  if ((fpclassify(opa) == FP_NAN) || (fpclassify(opb) == FP_NAN)) {
1038
    return 0;
1039
  }
1040
 
1041
  if isless(opa, opb) {
1042
    return 1;
1043
  }
1044
  else {
1045
    return 0;
1046
  }
1047
}
1048
 
1049
 
1050
/**********************************************************************//**
1051
 * Single-precision floating-point less-than-or-equal comparison
1052
 *
1053
 * @param[in] rs1 Source operand 1.
1054
 * @param[in] rs2 Source operand 2.
1055
 * @return Result.
1056
 **************************************************************************/
1057 56 zero_gravi
uint32_t __attribute__ ((noinline)) riscv_emulate_fles(float rs1, float rs2) {
1058 55 zero_gravi
 
1059
  float opa = subnormal_flush(rs1);
1060
  float opb = subnormal_flush(rs2);
1061
 
1062
  if ((fpclassify(opa) == FP_NAN) || (fpclassify(opb) == FP_NAN)) {
1063
    return 0;
1064
  }
1065
 
1066
  if islessequal(opa, opb) {
1067
    return 1;
1068
  }
1069
  else {
1070
    return 0;
1071
  }
1072
}
1073
 
1074
 
1075
/**********************************************************************//**
1076
 * Single-precision floating-point sign-injection
1077
 *
1078
 * @param[in] rs1 Source operand 1.
1079
 * @param[in] rs2 Source operand 2.
1080
 * @return Result.
1081
 **************************************************************************/
1082 56 zero_gravi
float __attribute__ ((noinline)) riscv_emulate_fsgnjs(float rs1, float rs2) {
1083 55 zero_gravi
 
1084
  float opa = subnormal_flush(rs1);
1085
  float opb = subnormal_flush(rs2);
1086
 
1087
  int sign_1 = (int)signbit(opa);
1088
  int sign_2 = (int)signbit(opb);
1089
  float res = 0;
1090
 
1091
  if (sign_2 != 0) { // opb is negative
1092
    if (sign_1 == 0) {
1093
      res = -opa;
1094
    }
1095
    else {
1096
      res = opa;
1097
    }
1098
  }
1099
  else { // opb is positive
1100
    if (sign_1 == 0) {
1101
      res = opa;
1102
    }
1103
    else {
1104
      res = -opa;
1105
    }
1106
  }
1107
 
1108
  return res;
1109
}
1110
 
1111
 
1112
/**********************************************************************//**
1113
 * Single-precision floating-point sign-injection NOT
1114
 *
1115
 * @param[in] rs1 Source operand 1.
1116
 * @param[in] rs2 Source operand 2.
1117
 * @return Result.
1118
 **************************************************************************/
1119 56 zero_gravi
float __attribute__ ((noinline)) riscv_emulate_fsgnjns(float rs1, float rs2) {
1120 55 zero_gravi
 
1121
  float opa = subnormal_flush(rs1);
1122
  float opb = subnormal_flush(rs2);
1123
 
1124
  int sign_1 = (int)signbit(opa);
1125
  int sign_2 = (int)signbit(opb);
1126
  float res = 0;
1127
 
1128
  if (sign_2 != 0) { // opb is negative
1129
    if (sign_1 == 0) {
1130
      res = opa;
1131
    }
1132
    else {
1133
      res = -opa;
1134
    }
1135
  }
1136
  else { // opb is positive
1137
    if (sign_1 == 0) {
1138
      res = -opa;
1139
    }
1140
    else {
1141
      res = opa;
1142
    }
1143
  }
1144
 
1145
  return res;
1146
}
1147
 
1148
 
1149
/**********************************************************************//**
1150
 * Single-precision floating-point sign-injection XOR
1151
 *
1152
 * @param[in] rs1 Source operand 1.
1153
 * @param[in] rs2 Source operand 2.
1154
 * @return Result.
1155
 **************************************************************************/
1156 56 zero_gravi
float __attribute__ ((noinline)) riscv_emulate_fsgnjxs(float rs1, float rs2) {
1157 55 zero_gravi
 
1158
  float opa = subnormal_flush(rs1);
1159
  float opb = subnormal_flush(rs2);
1160
 
1161
  int sign_1 = (int)signbit(opa);
1162
  int sign_2 = (int)signbit(opb);
1163
  float res = 0;
1164
 
1165
  if (((sign_1 == 0) && (sign_2 != 0)) || ((sign_1 != 0) && (sign_2 == 0))) {
1166
    if (sign_1 == 0) {
1167
      res = -opa;
1168
    }
1169
    else {
1170
      res = opa;
1171
    }
1172
  }
1173
  else {
1174
    if (sign_1 == 0) {
1175
      res = opa;
1176
    }
1177
    else {
1178
      res = -opa;
1179
    }
1180
  }
1181
 
1182
  return res;
1183
}
1184
 
1185
 
1186
/**********************************************************************//**
1187
 * Single-precision floating-point number classification
1188
 *
1189
 * @param[in] rs1 Source operand 1.
1190
 * @return Result.
1191
 **************************************************************************/
1192 56 zero_gravi
uint32_t __attribute__ ((noinline)) riscv_emulate_fclasss(float rs1) {
1193 55 zero_gravi
 
1194
  float opa = subnormal_flush(rs1);
1195
 
1196
  union {
1197
    uint32_t binary_value; /**< Access as native float */
1198
    float    float_value;  /**< Access in binary representation */
1199
  } aux;
1200
 
1201
  // RISC-V classify result layout
1202
  const uint32_t CLASS_NEG_INF    = 1 << 0; // negative infinity
1203
  const uint32_t CLASS_NEG_NORM   = 1 << 1; // negative normal number
1204
  const uint32_t CLASS_NEG_DENORM = 1 << 2; // negative subnormal number
1205
  const uint32_t CLASS_NEG_ZERO   = 1 << 3; // negative zero
1206
  const uint32_t CLASS_POS_ZERO   = 1 << 4; // positive zero
1207
  const uint32_t CLASS_POS_DENORM = 1 << 5; // positive subnormal number
1208
  const uint32_t CLASS_POS_NORM   = 1 << 6; // positive normal number
1209
  const uint32_t CLASS_POS_INF    = 1 << 7; // positive infinity
1210
  const uint32_t CLASS_SNAN       = 1 << 8; // signaling NaN (sNaN)
1211
  const uint32_t CLASS_QNAN       = 1 << 9; // quiet NaN (qNaN)
1212
 
1213
  int tmp = fpclassify(opa);
1214
  int sgn = (int)signbit(opa);
1215
 
1216
  uint32_t res = 0;
1217
 
1218
  // infinity
1219
  if (tmp == FP_INFINITE) {
1220
    if (sgn) { res |= CLASS_NEG_INF; }
1221
    else     { res |= CLASS_POS_INF; }
1222
  }
1223
 
1224
  // zero
1225
  if (tmp == FP_ZERO) {
1226
    if (sgn) { res |= CLASS_NEG_ZERO; }
1227
    else     { res |= CLASS_POS_ZERO; }
1228
  }
1229
 
1230
  // normal
1231
  if (tmp == FP_NORMAL) {
1232
    if (sgn) { res |= CLASS_NEG_NORM; }
1233
    else     { res |= CLASS_POS_NORM; }
1234
  }
1235
 
1236
  // subnormal
1237
  if (tmp == FP_SUBNORMAL) {
1238
    if (sgn) { res |= CLASS_NEG_DENORM; }
1239
    else     { res |= CLASS_POS_DENORM; }
1240
  }
1241
 
1242
  // NaN
1243
  if (tmp == FP_NAN) {
1244
    aux.float_value = opa;
1245
    if ((aux.binary_value >> 22) & 0b1) { // bit 22 (mantissa's MSB) is set -> canonical (quiet) NAN
1246
      res |= CLASS_QNAN;
1247
    }
1248
    else {
1249
      res |= CLASS_SNAN;
1250
    }
1251
  }
1252
 
1253
  return res;
1254
}
1255
 
1256
 
1257
/**********************************************************************//**
1258
 * Single-precision floating-point division
1259
 *
1260
 * @param[in] rs1 Source operand 1.
1261
 * @param[in] rs2 Source operand 2.
1262
 * @return Result.
1263
 **************************************************************************/
1264 56 zero_gravi
float __attribute__ ((noinline)) riscv_emulate_fdivs(float rs1, float rs2) {
1265 55 zero_gravi
 
1266
  float opa = subnormal_flush(rs1);
1267
  float opb = subnormal_flush(rs2);
1268
 
1269
  float res = opa / opb;
1270
  return subnormal_flush(res);
1271
}
1272
 
1273
 
1274
/**********************************************************************//**
1275
 * Single-precision floating-point square root
1276
 *
1277
 * @param[in] rs1 Source operand 1.
1278
 * @return Result.
1279
 **************************************************************************/
1280 56 zero_gravi
float __attribute__ ((noinline)) riscv_emulate_fsqrts(float rs1) {
1281 55 zero_gravi
 
1282
  float opa = subnormal_flush(rs1);
1283
 
1284
  float res = sqrtf(opa);
1285
  return subnormal_flush(res);
1286
}
1287
 
1288
 
1289
/**********************************************************************//**
1290
 * Single-precision floating-point fused multiply-add
1291
 *
1292
 * @note "noinline" attributed to make sure arguments/return values are in a0 and a1.
1293
 *
1294
 * @warning This instruction is not supported!
1295
 *
1296
 * @param[in] rs1 Source operand 1
1297
 * @param[in] rs2 Source operand 2
1298
 * @param[in] rs3 Source operand 3
1299
 * @return Result.
1300
 **************************************************************************/
1301 56 zero_gravi
float __attribute__ ((noinline)) riscv_emulate_fmadds(float rs1, float rs2, float rs3) {
1302 55 zero_gravi
 
1303
  float opa = subnormal_flush(rs1);
1304
  float opb = subnormal_flush(rs2);
1305
  float opc = subnormal_flush(rs3);
1306
 
1307
  float res = (opa * opb) + opc;
1308
  return subnormal_flush(res);
1309
}
1310
 
1311
 
1312
/**********************************************************************//**
1313
 * Single-precision floating-point fused multiply-sub
1314
 *
1315
 * @param[in] rs1 Source operand 1
1316
 * @param[in] rs2 Source operand 2
1317
 * @param[in] rs3 Source operand 3
1318
 * @return Result.
1319
 **************************************************************************/
1320 56 zero_gravi
float __attribute__ ((noinline)) riscv_emulate_fmsubs(float rs1, float rs2, float rs3) {
1321 55 zero_gravi
 
1322
  float opa = subnormal_flush(rs1);
1323
  float opb = subnormal_flush(rs2);
1324
  float opc = subnormal_flush(rs3);
1325
 
1326
  float res = (opa * opb) - opc;
1327
  return subnormal_flush(res);
1328
}
1329
 
1330
 
1331
/**********************************************************************//**
1332
 * Single-precision floating-point fused negated multiply-sub
1333
 *
1334
 * @param[in] rs1 Source operand 1
1335
 * @param[in] rs2 Source operand 2
1336
 * @param[in] rs3 Source operand 3
1337
 * @return Result.
1338
 **************************************************************************/
1339 56 zero_gravi
float __attribute__ ((noinline)) riscv_emulate_fnmsubs(float rs1, float rs2, float rs3) {
1340 55 zero_gravi
 
1341
  float opa = subnormal_flush(rs1);
1342
  float opb = subnormal_flush(rs2);
1343
  float opc = subnormal_flush(rs3);
1344
 
1345
  float res = -(opa * opb) + opc;
1346
  return subnormal_flush(res);
1347
}
1348
 
1349
 
1350
/**********************************************************************//**
1351
 * Single-precision floating-point fused negated multiply-add
1352
 *
1353
 * @param[in] rs1 Source operand 1
1354
 * @param[in] rs2 Source operand 2
1355
 * @param[in] rs3 Source operand 3
1356
 * @return Result.
1357
 **************************************************************************/
1358 56 zero_gravi
float __attribute__ ((noinline)) riscv_emulate_fnmadds(float rs1, float rs2, float rs3) {
1359 55 zero_gravi
 
1360
  float opa = subnormal_flush(rs1);
1361
  float opb = subnormal_flush(rs2);
1362
  float opc = subnormal_flush(rs3);
1363
 
1364
  float res = -(opa * opb) - opc;
1365
  return subnormal_flush(res);
1366
}
1367
 
1368
 
1369
#endif // neorv32_zfinx_extension_intrinsics_h
1370
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.