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 71

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

powered by: WebSVN 2.1.0

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