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 74

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 71 zero_gravi
// # Copyright (c) 2022, Stephan Nolting. All rights reserved.                                     #
10 55 zero_gravi
// #                                                                                               #
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 74 zero_gravi
 * Flush to zero if de-normal number.
90 55 zero_gravi
 *
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 74 zero_gravi
  // flush to zero if subnormal
101 55 zero_gravi
  if (fpclassify(tmp) == FP_SUBNORMAL) {
102
    if (signbit(tmp) != 0) {
103
      res = -0.0f;
104
    }
105
    else {
106
      res = +0.0f;
107
    }
108
  }
109
 
110
  return res;
111
}
112
 
113
 
114
// ################################################################################################
115
// Exception access
116
// ################################################################################################
117
 
118
/**********************************************************************//**
119
 * Get exception flags from fflags CSR (floating-point hardware).
120
 *
121
 * @return Floating point exception status word.
122
 **************************************************************************/
123
uint32_t get_hw_exceptions(void) {
124
 
125
  uint32_t res = neorv32_cpu_csr_read(CSR_FFLAGS);
126
 
127
  neorv32_cpu_csr_write(CSR_FFLAGS, 0); // clear status word
128
 
129
  return res;
130
}
131
 
132
 
133
/**********************************************************************//**
134
 * Get exception flags from C runtime (floating-point emulation).
135
 *
136
 * @warning WORK-IN-PROGRESS!
137
 *
138
 * @return Floating point exception status word.
139
 **************************************************************************/
140
uint32_t get_sw_exceptions(void) {
141
 
142
  const uint32_t FP_EXC_NV_C = 1 << 0; // invalid operation
143
  const uint32_t FP_EXC_DZ_C = 1 << 1; // divide by zero
144
  const uint32_t FP_EXC_OF_C = 1 << 2; // overflow
145
  const uint32_t FP_EXC_UF_C = 1 << 3; // underflow
146
  const uint32_t FP_EXC_NX_C = 1 << 4; // inexact
147
 
148
  int fpeRaised = fetestexcept(FE_ALL_EXCEPT);
149
 
150
  uint32_t res = 0;
151
 
152
  if (fpeRaised & FE_INVALID)   { res |= FP_EXC_NV_C; }
153
  if (fpeRaised & FE_DIVBYZERO) { res |= FP_EXC_DZ_C; }
154
  if (fpeRaised & FE_OVERFLOW)  { res |= FP_EXC_OF_C; }
155
  if (fpeRaised & FE_UNDERFLOW) { res |= FP_EXC_UF_C; }
156
  if (fpeRaised & FE_INEXACT)   { res |= FP_EXC_NX_C; }
157
 
158
  feclearexcept(FE_ALL_EXCEPT);
159
 
160
  return res;
161
}
162
 
163
 
164
// ################################################################################################
165
// "Intrinsics"
166
// ################################################################################################
167
 
168
/**********************************************************************//**
169
 * Single-precision floating-point addition
170
 *
171 71 zero_gravi
 * @param[in] rs1 Source operand 1.
172
 * @param[in] rs2 Source operand 2.
173 55 zero_gravi
 * @return Result.
174
 **************************************************************************/
175 56 zero_gravi
inline float __attribute__ ((always_inline)) riscv_intrinsic_fadds(float rs1, float rs2) {
176 55 zero_gravi
 
177
  float_conv_t opa, opb, res;
178
  opa.float_value = rs1;
179
  opb.float_value = rs2;
180
 
181 71 zero_gravi
  res.binary_value = CUSTOM_INSTR_R2_TYPE(0b0000000, opb.binary_value, opa.binary_value, 0b000, 0b1010011);
182 55 zero_gravi
  return res.float_value;
183
}
184
 
185
 
186
/**********************************************************************//**
187
 * Single-precision floating-point subtraction
188
 *
189 71 zero_gravi
 * @param[in] rs1 Source operand 1.
190
 * @param[in] rs2 Source operand 2.
191 55 zero_gravi
 * @return Result.
192
 **************************************************************************/
193 56 zero_gravi
inline float __attribute__ ((always_inline)) riscv_intrinsic_fsubs(float rs1, float rs2) {
194 55 zero_gravi
 
195
  float_conv_t opa, opb, res;
196
  opa.float_value = rs1;
197
  opb.float_value = rs2;
198
 
199 71 zero_gravi
  res.binary_value = CUSTOM_INSTR_R2_TYPE(0b0000100, opb.binary_value, opa.binary_value, 0b000, 0b1010011);
200 55 zero_gravi
  return res.float_value;
201
}
202
 
203
 
204
/**********************************************************************//**
205
 * Single-precision floating-point multiplication
206
 *
207 71 zero_gravi
 * @param[in] rs1 Source operand 1.
208
 * @param[in] rs2 Source operand 2.
209 55 zero_gravi
 * @return Result.
210
 **************************************************************************/
211 56 zero_gravi
inline float __attribute__ ((always_inline)) riscv_intrinsic_fmuls(float rs1, float rs2) {
212 55 zero_gravi
 
213
  float_conv_t opa, opb, res;
214
  opa.float_value = rs1;
215
  opb.float_value = rs2;
216
 
217 71 zero_gravi
  res.binary_value = CUSTOM_INSTR_R2_TYPE(0b0001000, opb.binary_value, opa.binary_value, 0b000, 0b1010011);
218 55 zero_gravi
  return res.float_value;
219
}
220
 
221
 
222
/**********************************************************************//**
223
 * Single-precision floating-point minimum
224
 *
225 71 zero_gravi
 * @param[in] rs1 Source operand 1.
226
 * @param[in] rs2 Source operand 2.
227 55 zero_gravi
 * @return Result.
228
 **************************************************************************/
229 56 zero_gravi
inline float __attribute__ ((always_inline)) riscv_intrinsic_fmins(float rs1, float rs2) {
230 55 zero_gravi
 
231
  float_conv_t opa, opb, res;
232
  opa.float_value = rs1;
233
  opb.float_value = rs2;
234
 
235 71 zero_gravi
  res.binary_value = CUSTOM_INSTR_R2_TYPE(0b0010100, opb.binary_value, opa.binary_value, 0b000, 0b1010011);
236 55 zero_gravi
  return res.float_value;
237
}
238
 
239
 
240
/**********************************************************************//**
241
 * Single-precision floating-point maximum
242
 *
243 71 zero_gravi
 * @param[in] rs1 Source operand 1.
244
 * @param[in] rs2 Source operand 2.
245 55 zero_gravi
 * @return Result.
246
 **************************************************************************/
247 56 zero_gravi
inline float __attribute__ ((always_inline)) riscv_intrinsic_fmaxs(float rs1, float rs2) {
248 55 zero_gravi
 
249
  float_conv_t opa, opb, res;
250
  opa.float_value = rs1;
251
  opb.float_value = rs2;
252
 
253 71 zero_gravi
  res.binary_value = CUSTOM_INSTR_R2_TYPE(0b0010100, opb.binary_value, opa.binary_value, 0b001, 0b1010011);
254 55 zero_gravi
  return res.float_value;
255
}
256
 
257
 
258
/**********************************************************************//**
259
 * Single-precision floating-point convert float to unsigned integer
260
 *
261 71 zero_gravi
 * @param[in] rs1 Source operand 1.
262 55 zero_gravi
 * @return Result.
263
 **************************************************************************/
264 56 zero_gravi
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_fcvt_wus(float rs1) {
265 55 zero_gravi
 
266
  float_conv_t opa;
267
  opa.float_value = rs1;
268
 
269 71 zero_gravi
  return CUSTOM_INSTR_R1_TYPE(0b1100000, 0b00001, opa.binary_value, 0b000, 0b1010011);
270 55 zero_gravi
}
271
 
272
 
273
/**********************************************************************//**
274
 * Single-precision floating-point convert float to signed integer
275
 *
276 71 zero_gravi
 * @param[in] rs1 Source operand 1.
277 55 zero_gravi
 * @return Result.
278
 **************************************************************************/
279 56 zero_gravi
inline int32_t __attribute__ ((always_inline)) riscv_intrinsic_fcvt_ws(float rs1) {
280 55 zero_gravi
 
281
  float_conv_t opa;
282
  opa.float_value = rs1;
283
 
284 71 zero_gravi
  return (int32_t)CUSTOM_INSTR_R1_TYPE(0b1100000, 0b00000, opa.binary_value, 0b000, 0b1010011);
285 55 zero_gravi
}
286
 
287
 
288
/**********************************************************************//**
289
 * Single-precision floating-point convert unsigned integer to float
290
 *
291 71 zero_gravi
 * @param[in] rs1 Source operand 1.
292 55 zero_gravi
 * @return Result.
293
 **************************************************************************/
294 56 zero_gravi
inline float __attribute__ ((always_inline)) riscv_intrinsic_fcvt_swu(uint32_t rs1) {
295 55 zero_gravi
 
296
  float_conv_t res;
297
 
298 71 zero_gravi
  res.binary_value = CUSTOM_INSTR_R1_TYPE(0b1101000, 0b00001, rs1, 0b000, 0b1010011);
299 55 zero_gravi
  return res.float_value;
300
}
301
 
302
 
303
/**********************************************************************//**
304
 * Single-precision floating-point convert signed integer to float
305
 *
306 71 zero_gravi
 * @param[in] rs1 Source operand 1.
307 55 zero_gravi
 * @return Result.
308
 **************************************************************************/
309 56 zero_gravi
inline float __attribute__ ((always_inline)) riscv_intrinsic_fcvt_sw(int32_t rs1) {
310 55 zero_gravi
 
311
  float_conv_t res;
312
 
313 71 zero_gravi
  res.binary_value = CUSTOM_INSTR_R1_TYPE(0b1101000, 0b00000, rs1, 0b000, 0b1010011);
314 55 zero_gravi
  return res.float_value;
315
}
316
 
317
 
318
/**********************************************************************//**
319
 * Single-precision floating-point equal comparison
320
 *
321 71 zero_gravi
 * @param[in] rs1 Source operand 1.
322
 * @param[in] rs2 Source operand 2.
323 55 zero_gravi
 * @return Result.
324
 **************************************************************************/
325 56 zero_gravi
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_feqs(float rs1, float rs2) {
326 55 zero_gravi
 
327
  float_conv_t opa, opb;
328
  opa.float_value = rs1;
329
  opb.float_value = rs2;
330
 
331 71 zero_gravi
  return CUSTOM_INSTR_R2_TYPE(0b1010000, opb.binary_value, opa.binary_value, 0b010, 0b1010011);
332 55 zero_gravi
}
333
 
334
 
335
/**********************************************************************//**
336
 * Single-precision floating-point less-than comparison
337
 *
338 71 zero_gravi
 * @param[in] rs1 Source operand 1.
339
 * @param[in] rs2 Source operand 2.
340 55 zero_gravi
 * @return Result.
341
 **************************************************************************/
342 56 zero_gravi
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_flts(float rs1, float rs2) {
343 55 zero_gravi
 
344
  float_conv_t opa, opb;
345
  opa.float_value = rs1;
346
  opb.float_value = rs2;
347
 
348 71 zero_gravi
  return CUSTOM_INSTR_R2_TYPE(0b1010000, opb.binary_value, opa.binary_value, 0b001, 0b1010011);
349 55 zero_gravi
}
350
 
351
 
352
/**********************************************************************//**
353
 * Single-precision floating-point less-than-or-equal comparison
354
 *
355 71 zero_gravi
 * @param[in] rs1 Source operand 1.
356
 * @param[in] rs2 Source operand 2.
357 55 zero_gravi
 * @return Result.
358
 **************************************************************************/
359 56 zero_gravi
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_fles(float rs1, float rs2) {
360 55 zero_gravi
 
361
  float_conv_t opa, opb;
362
  opa.float_value = rs1;
363
  opb.float_value = rs2;
364
 
365 71 zero_gravi
  return CUSTOM_INSTR_R2_TYPE(0b1010000, opb.binary_value, opa.binary_value, 0b000, 0b1010011);
366 55 zero_gravi
}
367
 
368
 
369
/**********************************************************************//**
370
 * Single-precision floating-point sign-injection
371
 *
372 71 zero_gravi
 * @param[in] rs1 Source operand 1.
373
 * @param[in] rs2 Source operand 2.
374 55 zero_gravi
 * @return Result.
375
 **************************************************************************/
376 56 zero_gravi
inline float __attribute__ ((always_inline)) riscv_intrinsic_fsgnjs(float rs1, float rs2) {
377 55 zero_gravi
 
378
  float_conv_t opa, opb, res;
379
  opa.float_value = rs1;
380
  opb.float_value = rs2;
381
 
382 71 zero_gravi
  res.binary_value = CUSTOM_INSTR_R2_TYPE(0b0010000, opb.binary_value, opa.binary_value, 0b000, 0b1010011);
383 55 zero_gravi
  return res.float_value;
384
}
385
 
386
 
387
/**********************************************************************//**
388
 * Single-precision floating-point sign-injection NOT
389
 *
390 71 zero_gravi
 * @param[in] rs1 Source operand 1.
391
 * @param[in] rs2 Source operand 2.
392 55 zero_gravi
 * @return Result.
393
 **************************************************************************/
394 56 zero_gravi
inline float __attribute__ ((always_inline)) riscv_intrinsic_fsgnjns(float rs1, float rs2) {
395 55 zero_gravi
 
396
  float_conv_t opa, opb, res;
397
  opa.float_value = rs1;
398
  opb.float_value = rs2;
399
 
400 71 zero_gravi
  res.binary_value = CUSTOM_INSTR_R2_TYPE(0b0010000, opb.binary_value, opa.binary_value, 0b001, 0b1010011);
401 55 zero_gravi
  return res.float_value;
402
}
403
 
404
 
405
/**********************************************************************//**
406
 * Single-precision floating-point sign-injection XOR
407
 *
408 71 zero_gravi
 * @param[in] rs1 Source operand 1.
409
 * @param[in] rs2 Source operand 2.
410 55 zero_gravi
 * @return Result.
411
 **************************************************************************/
412 56 zero_gravi
inline float __attribute__ ((always_inline)) riscv_intrinsic_fsgnjxs(float rs1, float rs2) {
413 55 zero_gravi
 
414
  float_conv_t opa, opb, res;
415
  opa.float_value = rs1;
416
  opb.float_value = rs2;
417
 
418 71 zero_gravi
  res.binary_value = CUSTOM_INSTR_R2_TYPE(0b0010000, opb.binary_value, opa.binary_value, 0b010, 0b1010011);
419 55 zero_gravi
  return res.float_value;
420
}
421
 
422
 
423
/**********************************************************************//**
424
 * Single-precision floating-point number classification
425
 *
426 71 zero_gravi
 * @param[in] rs1 Source operand 1.
427 55 zero_gravi
 * @return Result.
428
 **************************************************************************/
429 56 zero_gravi
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_fclasss(float rs1) {
430 55 zero_gravi
 
431
  float_conv_t opa;
432
  opa.float_value = rs1;
433
 
434 71 zero_gravi
  return CUSTOM_INSTR_R1_TYPE(0b1110000, 0b00000, opa.binary_value, 0b001, 0b1010011);
435 55 zero_gravi
}
436
 
437
 
438
// ################################################################################################
439
// !!! UNSUPPORTED instructions !!!
440
// ################################################################################################
441
 
442
/**********************************************************************//**
443
 * Single-precision floating-point division
444
 *
445
 * @warning This instruction is not supported and should raise an illegal instruction exception when executed.
446
 *
447 71 zero_gravi
 * @param[in] rs1 Source operand 1.
448
 * @param[in] rs2 Source operand 2.
449 55 zero_gravi
 * @return Result.
450
 **************************************************************************/
451 56 zero_gravi
inline float __attribute__ ((always_inline)) riscv_intrinsic_fdivs(float rs1, float rs2) {
452 55 zero_gravi
 
453
  float_conv_t opa, opb, res;
454
  opa.float_value = rs1;
455
  opb.float_value = rs2;
456
 
457 71 zero_gravi
  res.binary_value = CUSTOM_INSTR_R2_TYPE(0b0001100, opb.binary_value, opa.binary_value, 0b000, 0b1010011);
458 55 zero_gravi
  return res.float_value;
459
}
460
 
461
 
462
/**********************************************************************//**
463
 * Single-precision floating-point square root
464
 *
465
 * @warning This instruction is not supported and should raise an illegal instruction exception when executed.
466
 *
467 71 zero_gravi
 * @param[in] rs1 Source operand 1.
468 55 zero_gravi
 * @return Result.
469
 **************************************************************************/
470 56 zero_gravi
inline float __attribute__ ((always_inline)) riscv_intrinsic_fsqrts(float rs1) {
471 55 zero_gravi
 
472
  float_conv_t opa, res;
473
  opa.float_value = rs1;
474
 
475 71 zero_gravi
  res.binary_value = CUSTOM_INSTR_R1_TYPE(0b0101100, 0b00000, opa.binary_value, 0b000, 0b1010011);
476 55 zero_gravi
  return res.float_value;
477
}
478
 
479
 
480
/**********************************************************************//**
481
 * Single-precision floating-point fused multiply-add
482
 *
483
 * @warning This instruction is not supported and should raise an illegal instruction exception when executed.
484
 *
485 71 zero_gravi
 * @param[in] rs1 Source operand 1
486
 * @param[in] rs2 Source operand 2
487
 * @param[in] rs3 Source operand 3
488 55 zero_gravi
 * @return Result.
489
 **************************************************************************/
490 56 zero_gravi
inline float __attribute__ ((always_inline)) riscv_intrinsic_fmadds(float rs1, float rs2, float rs3) {
491 55 zero_gravi
 
492
  float_conv_t opa, opb, opc, res;
493
  opa.float_value = rs1;
494
  opb.float_value = rs2;
495
  opc.float_value = rs3;
496
 
497 71 zero_gravi
  res.binary_value = CUSTOM_INSTR_R3_TYPE(opc.binary_value, opb.binary_value, opa.binary_value, 0b000, 0b1000011);
498 55 zero_gravi
  return res.float_value;
499
}
500
 
501
 
502
/**********************************************************************//**
503
 * Single-precision floating-point fused multiply-sub
504
 *
505
 * @warning This instruction is not supported and should raise an illegal instruction exception when executed.
506
 *
507 71 zero_gravi
 * @param[in] rs1 Source operand 1
508
 * @param[in] rs2 Source operand 2
509
 * @param[in] rs3 Source operand 3
510 55 zero_gravi
 * @return Result.
511
 **************************************************************************/
512 56 zero_gravi
inline float __attribute__ ((always_inline)) riscv_intrinsic_fmsubs(float rs1, float rs2, float rs3) {
513 55 zero_gravi
 
514
  float_conv_t opa, opb, opc, res;
515
  opa.float_value = rs1;
516
  opb.float_value = rs2;
517
  opc.float_value = rs3;
518
 
519 71 zero_gravi
  res.binary_value = CUSTOM_INSTR_R3_TYPE(opc.binary_value, opb.binary_value, opa.binary_value, 0b000, 0b1000111);
520 55 zero_gravi
  return res.float_value;
521
}
522
 
523
 
524
/**********************************************************************//**
525
 * Single-precision floating-point fused negated multiply-sub
526
 *
527
 * @warning This instruction is not supported and should raise an illegal instruction exception when executed.
528
 *
529 71 zero_gravi
 * @param[in] rs1 Source operand 1
530
 * @param[in] rs2 Source operand 2
531
 * @param[in] rs3 Source operand 3
532 55 zero_gravi
 * @return Result.
533
 **************************************************************************/
534 56 zero_gravi
inline float __attribute__ ((always_inline)) riscv_intrinsic_fnmsubs(float rs1, float rs2, float rs3) {
535 55 zero_gravi
 
536
  float_conv_t opa, opb, opc, res;
537
  opa.float_value = rs1;
538
  opb.float_value = rs2;
539
  opc.float_value = rs3;
540
 
541 71 zero_gravi
  res.binary_value = CUSTOM_INSTR_R3_TYPE(opc.binary_value, opb.binary_value, opa.binary_value, 0b000, 0b1001011);
542 55 zero_gravi
  return res.float_value;
543
}
544
 
545
 
546
/**********************************************************************//**
547
 * Single-precision floating-point fused negated multiply-add
548
 *
549
 * @warning This instruction is not supported and should raise an illegal instruction exception when executed.
550
 *
551 71 zero_gravi
 * @param[in] rs1 Source operand 1
552
 * @param[in] rs2 Source operand 2
553
 * @param[in] rs3 Source operand 3
554 55 zero_gravi
 * @return Result.
555
 **************************************************************************/
556 56 zero_gravi
inline float __attribute__ ((always_inline)) riscv_intrinsic_fnmadds(float rs1, float rs2, float rs3) {
557 55 zero_gravi
 
558
  float_conv_t opa, opb, opc, res;
559
  opa.float_value = rs1;
560
  opb.float_value = rs2;
561
  opc.float_value = rs3;
562
 
563 71 zero_gravi
  res.binary_value = CUSTOM_INSTR_R3_TYPE(opc.binary_value, opb.binary_value, opa.binary_value, 0b000, 0b1001111);
564 55 zero_gravi
  return res.float_value;
565
}
566
 
567
 
568
// ################################################################################################
569
// Emulation functions
570
// ################################################################################################
571
 
572
/**********************************************************************//**
573
 * Single-precision floating-point addition
574
 *
575
 * @param[in] rs1 Source operand 1.
576
 * @param[in] rs2 Source operand 2.
577
 * @return Result.
578
 **************************************************************************/
579 56 zero_gravi
float __attribute__ ((noinline)) riscv_emulate_fadds(float rs1, float rs2) {
580 55 zero_gravi
 
581
  float opa = subnormal_flush(rs1);
582
  float opb = subnormal_flush(rs2);
583
 
584
  float res = opa + opb;
585 74 zero_gravi
 
586
  // make NAN canonical
587
  if (fpclassify(res) == FP_NAN) {
588
    res = NAN;
589
  }
590
 
591 55 zero_gravi
  return subnormal_flush(res);
592
}
593
 
594
 
595
/**********************************************************************//**
596
 * Single-precision floating-point subtraction
597
 *
598
 * @param[in] rs1 Source operand 1.
599
 * @param[in] rs2 Source operand 2.
600
 * @return Result.
601
 **************************************************************************/
602 56 zero_gravi
float __attribute__ ((noinline)) riscv_emulate_fsubs(float rs1, float rs2) {
603 55 zero_gravi
 
604
  float opa = subnormal_flush(rs1);
605
  float opb = subnormal_flush(rs2);
606
 
607
  float res = opa - opb;
608 74 zero_gravi
 
609
  // make NAN canonical
610
  if (fpclassify(res) == FP_NAN) {
611
    res = NAN;
612
  }
613
 
614 55 zero_gravi
  return subnormal_flush(res);
615
}
616
 
617
 
618
/**********************************************************************//**
619
 * Single-precision floating-point multiplication
620
 *
621
 * @param[in] rs1 Source operand 1.
622
 * @param[in] rs2 Source operand 2.
623
 * @return Result.
624
 **************************************************************************/
625 56 zero_gravi
float __attribute__ ((noinline)) riscv_emulate_fmuls(float rs1, float rs2) {
626 55 zero_gravi
 
627
  float opa = subnormal_flush(rs1);
628
  float opb = subnormal_flush(rs2);
629
 
630
  float res = opa * opb;
631
  return subnormal_flush(res);
632
}
633
 
634
 
635
/**********************************************************************//**
636
 * Single-precision floating-point minimum
637
 *
638
 * @param[in] rs1 Source operand 1.
639
 * @param[in] rs2 Source operand 2.
640
 * @return Result.
641
 **************************************************************************/
642 56 zero_gravi
float __attribute__ ((noinline)) riscv_emulate_fmins(float rs1, float rs2) {
643 55 zero_gravi
 
644
  float opa = subnormal_flush(rs1);
645
  float opb = subnormal_flush(rs2);
646
 
647
  union {
648
  uint32_t binary_value; /**< Access as native float */
649
  float    float_value;  /**< Access in binary representation */
650
  } tmp_a, tmp_b;
651
 
652
  if ((fpclassify(opa) == FP_NAN) && (fpclassify(opb) == FP_NAN)) {
653
    return nanf("");
654
  }
655
 
656
  if (fpclassify(opa) == FP_NAN) {
657
    return opb;
658
  }
659
 
660
  if (fpclassify(opb) == FP_NAN) {
661
    return opa;
662
  }
663
 
664
  // RISC-V spec: -0 < +0
665
  tmp_a.float_value = opa;
666
  tmp_b.float_value = opb;
667
  if (((tmp_a.binary_value == 0x80000000) && (tmp_b.binary_value == 0x00000000)) ||
668
      ((tmp_a.binary_value == 0x00000000) && (tmp_b.binary_value == 0x80000000))) {
669
    return -0.0f;
670
  }
671
 
672
  return fmin(opa, opb);
673
}
674
 
675
 
676
/**********************************************************************//**
677
 * Single-precision floating-point maximum
678
 *
679
 * @param[in] rs1 Source operand 1.
680
 * @param[in] rs2 Source operand 2.
681
 * @return Result.
682
 **************************************************************************/
683 56 zero_gravi
float __attribute__ ((noinline)) riscv_emulate_fmaxs(float rs1, float rs2) {
684 55 zero_gravi
 
685
  float opa = subnormal_flush(rs1);
686
  float opb = subnormal_flush(rs2);
687
 
688
  union {
689
  uint32_t binary_value; /**< Access as native float */
690
  float    float_value;  /**< Access in binary representation */
691
  } tmp_a, tmp_b;
692
 
693
 
694
  if ((fpclassify(opa) == FP_NAN) && (fpclassify(opb) == FP_NAN)) {
695
    return nanf("");
696
  }
697
 
698
  if (fpclassify(opa) == FP_NAN) {
699
    return opb;
700
  }
701
 
702
  if (fpclassify(opb) == FP_NAN) {
703
    return opa;
704
  }
705
 
706
  // RISC-V spec: -0 < +0
707
  tmp_a.float_value = opa;
708
  tmp_b.float_value = opb;
709
  if (((tmp_a.binary_value == 0x80000000) && (tmp_b.binary_value == 0x00000000)) ||
710
      ((tmp_a.binary_value == 0x00000000) && (tmp_b.binary_value == 0x80000000))) {
711
    return +0.0f;
712
  }
713
 
714
  return fmax(opa, opb);
715
}
716
 
717
 
718
/**********************************************************************//**
719
 * Single-precision floating-point float to unsigned integer
720
 *
721
 * @param[in] rs1 Source operand 1.
722
 * @return Result.
723
 **************************************************************************/
724 56 zero_gravi
uint32_t __attribute__ ((noinline)) riscv_emulate_fcvt_wus(float rs1) {
725 55 zero_gravi
 
726
  float opa = subnormal_flush(rs1);
727
 
728
  return (uint32_t)roundf(opa);
729
}
730
 
731
 
732
/**********************************************************************//**
733
 * Single-precision floating-point float to signed integer
734
 *
735
 * @param[in] rs1 Source operand 1.
736
 * @return Result.
737
 **************************************************************************/
738 56 zero_gravi
int32_t __attribute__ ((noinline)) riscv_emulate_fcvt_ws(float rs1) {
739 55 zero_gravi
 
740
  float opa = subnormal_flush(rs1);
741
 
742
  return (int32_t)roundf(opa);
743
}
744
 
745
 
746
/**********************************************************************//**
747
 * Single-precision floating-point unsigned integer to float
748
 *
749
 * @param[in] rs1 Source operand 1.
750
 * @return Result.
751
 **************************************************************************/
752 56 zero_gravi
float __attribute__ ((noinline)) riscv_emulate_fcvt_swu(uint32_t rs1) {
753 55 zero_gravi
 
754
  return (float)rs1;
755
}
756
 
757
 
758
/**********************************************************************//**
759
 * Single-precision floating-point signed integer to float
760
 *
761
 * @param[in] rs1 Source operand 1.
762
 * @return Result.
763
 **************************************************************************/
764 56 zero_gravi
float __attribute__ ((noinline)) riscv_emulate_fcvt_sw(int32_t rs1) {
765 55 zero_gravi
 
766
  return (float)rs1;
767
}
768
 
769
 
770
/**********************************************************************//**
771
 * Single-precision floating-point equal comparison
772
 *
773
 * @param[in] rs1 Source operand 1.
774
 * @param[in] rs2 Source operand 2.
775
 * @return Result.
776
 **************************************************************************/
777 56 zero_gravi
uint32_t __attribute__ ((noinline)) riscv_emulate_feqs(float rs1, float rs2) {
778 55 zero_gravi
 
779
  float opa = subnormal_flush(rs1);
780
  float opb = subnormal_flush(rs2);
781
 
782
  if ((fpclassify(opa) == FP_NAN) || (fpclassify(opb) == FP_NAN)) {
783
    return 0;
784
  }
785
 
786
  if isless(opa, opb) {
787
    return 0;
788
  }
789
  else if isgreater(opa, opb) {
790
    return 0;
791
  }
792
  else {
793
    return 1;
794
  }
795
}
796
 
797
 
798
/**********************************************************************//**
799
 * Single-precision floating-point less-than comparison
800
 *
801
 * @param[in] rs1 Source operand 1.
802
 * @param[in] rs2 Source operand 2.
803
 * @return Result.
804
 **************************************************************************/
805 56 zero_gravi
uint32_t __attribute__ ((noinline)) riscv_emulate_flts(float rs1, float rs2) {
806 55 zero_gravi
 
807
  float opa = subnormal_flush(rs1);
808
  float opb = subnormal_flush(rs2);
809
 
810
  if ((fpclassify(opa) == FP_NAN) || (fpclassify(opb) == FP_NAN)) {
811
    return 0;
812
  }
813
 
814
  if isless(opa, opb) {
815
    return 1;
816
  }
817
  else {
818
    return 0;
819
  }
820
}
821
 
822
 
823
/**********************************************************************//**
824
 * Single-precision floating-point less-than-or-equal comparison
825
 *
826
 * @param[in] rs1 Source operand 1.
827
 * @param[in] rs2 Source operand 2.
828
 * @return Result.
829
 **************************************************************************/
830 56 zero_gravi
uint32_t __attribute__ ((noinline)) riscv_emulate_fles(float rs1, float rs2) {
831 55 zero_gravi
 
832
  float opa = subnormal_flush(rs1);
833
  float opb = subnormal_flush(rs2);
834
 
835
  if ((fpclassify(opa) == FP_NAN) || (fpclassify(opb) == FP_NAN)) {
836
    return 0;
837
  }
838
 
839
  if islessequal(opa, opb) {
840
    return 1;
841
  }
842
  else {
843
    return 0;
844
  }
845
}
846
 
847
 
848
/**********************************************************************//**
849
 * Single-precision floating-point sign-injection
850
 *
851
 * @param[in] rs1 Source operand 1.
852
 * @param[in] rs2 Source operand 2.
853
 * @return Result.
854
 **************************************************************************/
855 56 zero_gravi
float __attribute__ ((noinline)) riscv_emulate_fsgnjs(float rs1, float rs2) {
856 55 zero_gravi
 
857
  float opa = subnormal_flush(rs1);
858
  float opb = subnormal_flush(rs2);
859
 
860
  int sign_1 = (int)signbit(opa);
861
  int sign_2 = (int)signbit(opb);
862
  float res = 0;
863
 
864
  if (sign_2 != 0) { // opb is negative
865
    if (sign_1 == 0) {
866
      res = -opa;
867
    }
868
    else {
869
      res = opa;
870
    }
871
  }
872
  else { // opb is positive
873
    if (sign_1 == 0) {
874
      res = opa;
875
    }
876
    else {
877
      res = -opa;
878
    }
879
  }
880
 
881
  return res;
882
}
883
 
884
 
885
/**********************************************************************//**
886
 * Single-precision floating-point sign-injection NOT
887
 *
888
 * @param[in] rs1 Source operand 1.
889
 * @param[in] rs2 Source operand 2.
890
 * @return Result.
891
 **************************************************************************/
892 56 zero_gravi
float __attribute__ ((noinline)) riscv_emulate_fsgnjns(float rs1, float rs2) {
893 55 zero_gravi
 
894
  float opa = subnormal_flush(rs1);
895
  float opb = subnormal_flush(rs2);
896
 
897
  int sign_1 = (int)signbit(opa);
898
  int sign_2 = (int)signbit(opb);
899
  float res = 0;
900
 
901
  if (sign_2 != 0) { // opb is negative
902
    if (sign_1 == 0) {
903
      res = opa;
904
    }
905
    else {
906
      res = -opa;
907
    }
908
  }
909
  else { // opb is positive
910
    if (sign_1 == 0) {
911
      res = -opa;
912
    }
913
    else {
914
      res = opa;
915
    }
916
  }
917
 
918
  return res;
919
}
920
 
921
 
922
/**********************************************************************//**
923
 * Single-precision floating-point sign-injection XOR
924
 *
925
 * @param[in] rs1 Source operand 1.
926
 * @param[in] rs2 Source operand 2.
927
 * @return Result.
928
 **************************************************************************/
929 56 zero_gravi
float __attribute__ ((noinline)) riscv_emulate_fsgnjxs(float rs1, float rs2) {
930 55 zero_gravi
 
931
  float opa = subnormal_flush(rs1);
932
  float opb = subnormal_flush(rs2);
933
 
934
  int sign_1 = (int)signbit(opa);
935
  int sign_2 = (int)signbit(opb);
936
  float res = 0;
937
 
938
  if (((sign_1 == 0) && (sign_2 != 0)) || ((sign_1 != 0) && (sign_2 == 0))) {
939
    if (sign_1 == 0) {
940
      res = -opa;
941
    }
942
    else {
943
      res = opa;
944
    }
945
  }
946
  else {
947
    if (sign_1 == 0) {
948
      res = opa;
949
    }
950
    else {
951
      res = -opa;
952
    }
953
  }
954
 
955
  return res;
956
}
957
 
958
 
959
/**********************************************************************//**
960
 * Single-precision floating-point number classification
961
 *
962
 * @param[in] rs1 Source operand 1.
963
 * @return Result.
964
 **************************************************************************/
965 56 zero_gravi
uint32_t __attribute__ ((noinline)) riscv_emulate_fclasss(float rs1) {
966 55 zero_gravi
 
967
  float opa = subnormal_flush(rs1);
968
 
969
  union {
970
    uint32_t binary_value; /**< Access as native float */
971
    float    float_value;  /**< Access in binary representation */
972
  } aux;
973
 
974
  // RISC-V classify result layout
975
  const uint32_t CLASS_NEG_INF    = 1 << 0; // negative infinity
976
  const uint32_t CLASS_NEG_NORM   = 1 << 1; // negative normal number
977
  const uint32_t CLASS_NEG_DENORM = 1 << 2; // negative subnormal number
978
  const uint32_t CLASS_NEG_ZERO   = 1 << 3; // negative zero
979
  const uint32_t CLASS_POS_ZERO   = 1 << 4; // positive zero
980
  const uint32_t CLASS_POS_DENORM = 1 << 5; // positive subnormal number
981
  const uint32_t CLASS_POS_NORM   = 1 << 6; // positive normal number
982
  const uint32_t CLASS_POS_INF    = 1 << 7; // positive infinity
983
  const uint32_t CLASS_SNAN       = 1 << 8; // signaling NaN (sNaN)
984
  const uint32_t CLASS_QNAN       = 1 << 9; // quiet NaN (qNaN)
985
 
986
  int tmp = fpclassify(opa);
987
  int sgn = (int)signbit(opa);
988
 
989
  uint32_t res = 0;
990
 
991
  // infinity
992
  if (tmp == FP_INFINITE) {
993
    if (sgn) { res |= CLASS_NEG_INF; }
994
    else     { res |= CLASS_POS_INF; }
995
  }
996
 
997
  // zero
998
  if (tmp == FP_ZERO) {
999
    if (sgn) { res |= CLASS_NEG_ZERO; }
1000
    else     { res |= CLASS_POS_ZERO; }
1001
  }
1002
 
1003
  // normal
1004
  if (tmp == FP_NORMAL) {
1005
    if (sgn) { res |= CLASS_NEG_NORM; }
1006
    else     { res |= CLASS_POS_NORM; }
1007
  }
1008
 
1009
  // subnormal
1010
  if (tmp == FP_SUBNORMAL) {
1011
    if (sgn) { res |= CLASS_NEG_DENORM; }
1012
    else     { res |= CLASS_POS_DENORM; }
1013
  }
1014
 
1015
  // NaN
1016
  if (tmp == FP_NAN) {
1017
    aux.float_value = opa;
1018
    if ((aux.binary_value >> 22) & 0b1) { // bit 22 (mantissa's MSB) is set -> canonical (quiet) NAN
1019
      res |= CLASS_QNAN;
1020
    }
1021
    else {
1022
      res |= CLASS_SNAN;
1023
    }
1024
  }
1025
 
1026
  return res;
1027
}
1028
 
1029
 
1030
/**********************************************************************//**
1031
 * Single-precision floating-point division
1032
 *
1033
 * @param[in] rs1 Source operand 1.
1034
 * @param[in] rs2 Source operand 2.
1035
 * @return Result.
1036
 **************************************************************************/
1037 56 zero_gravi
float __attribute__ ((noinline)) riscv_emulate_fdivs(float rs1, float rs2) {
1038 55 zero_gravi
 
1039
  float opa = subnormal_flush(rs1);
1040
  float opb = subnormal_flush(rs2);
1041
 
1042
  float res = opa / opb;
1043
  return subnormal_flush(res);
1044
}
1045
 
1046
 
1047
/**********************************************************************//**
1048
 * Single-precision floating-point square root
1049
 *
1050
 * @param[in] rs1 Source operand 1.
1051
 * @return Result.
1052
 **************************************************************************/
1053 56 zero_gravi
float __attribute__ ((noinline)) riscv_emulate_fsqrts(float rs1) {
1054 55 zero_gravi
 
1055
  float opa = subnormal_flush(rs1);
1056
 
1057
  float res = sqrtf(opa);
1058
  return subnormal_flush(res);
1059
}
1060
 
1061
 
1062
/**********************************************************************//**
1063
 * Single-precision floating-point fused multiply-add
1064
 *
1065
 * @warning This instruction is not supported!
1066
 *
1067
 * @param[in] rs1 Source operand 1
1068
 * @param[in] rs2 Source operand 2
1069
 * @param[in] rs3 Source operand 3
1070
 * @return Result.
1071
 **************************************************************************/
1072 56 zero_gravi
float __attribute__ ((noinline)) riscv_emulate_fmadds(float rs1, float rs2, float rs3) {
1073 55 zero_gravi
 
1074
  float opa = subnormal_flush(rs1);
1075
  float opb = subnormal_flush(rs2);
1076
  float opc = subnormal_flush(rs3);
1077
 
1078
  float res = (opa * opb) + opc;
1079
  return subnormal_flush(res);
1080
}
1081
 
1082
 
1083
/**********************************************************************//**
1084
 * Single-precision floating-point fused multiply-sub
1085
 *
1086
 * @param[in] rs1 Source operand 1
1087
 * @param[in] rs2 Source operand 2
1088
 * @param[in] rs3 Source operand 3
1089
 * @return Result.
1090
 **************************************************************************/
1091 56 zero_gravi
float __attribute__ ((noinline)) riscv_emulate_fmsubs(float rs1, float rs2, float rs3) {
1092 55 zero_gravi
 
1093
  float opa = subnormal_flush(rs1);
1094
  float opb = subnormal_flush(rs2);
1095
  float opc = subnormal_flush(rs3);
1096
 
1097
  float res = (opa * opb) - opc;
1098
  return subnormal_flush(res);
1099
}
1100
 
1101
 
1102
/**********************************************************************//**
1103
 * Single-precision floating-point fused negated multiply-sub
1104
 *
1105
 * @param[in] rs1 Source operand 1
1106
 * @param[in] rs2 Source operand 2
1107
 * @param[in] rs3 Source operand 3
1108
 * @return Result.
1109
 **************************************************************************/
1110 56 zero_gravi
float __attribute__ ((noinline)) riscv_emulate_fnmsubs(float rs1, float rs2, float rs3) {
1111 55 zero_gravi
 
1112
  float opa = subnormal_flush(rs1);
1113
  float opb = subnormal_flush(rs2);
1114
  float opc = subnormal_flush(rs3);
1115
 
1116
  float res = -(opa * opb) + opc;
1117
  return subnormal_flush(res);
1118
}
1119
 
1120
 
1121
/**********************************************************************//**
1122
 * Single-precision floating-point fused negated multiply-add
1123
 *
1124
 * @param[in] rs1 Source operand 1
1125
 * @param[in] rs2 Source operand 2
1126
 * @param[in] rs3 Source operand 3
1127
 * @return Result.
1128
 **************************************************************************/
1129 56 zero_gravi
float __attribute__ ((noinline)) riscv_emulate_fnmadds(float rs1, float rs2, float rs3) {
1130 55 zero_gravi
 
1131
  float opa = subnormal_flush(rs1);
1132
  float opb = subnormal_flush(rs2);
1133
  float opc = subnormal_flush(rs3);
1134
 
1135
  float res = -(opa * opb) - opc;
1136
  return subnormal_flush(res);
1137
}
1138
 
1139
 
1140
#endif // neorv32_zfinx_extension_intrinsics_h
1141
 

powered by: WebSVN 2.1.0

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