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

Subversion Repositories neorv32

[/] [neorv32/] [trunk/] [sw/] [example/] [floating_point_test/] [main.c] - Blame information for rev 60

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

Line No. Rev Author Line
1 55 zero_gravi
// #################################################################################################
2
// # << NEORV32 - RISC-V Single-Precision Floating-Point 'Zfinx' Extension Verification Program >> #
3
// # ********************************************************************************************* #
4
// # BSD 3-Clause License                                                                          #
5
// #                                                                                               #
6
// # Copyright (c) 2021, Stephan Nolting. All rights reserved.                                     #
7
// #                                                                                               #
8
// # Redistribution and use in source and binary forms, with or without modification, are          #
9
// # permitted provided that the following conditions are met:                                     #
10
// #                                                                                               #
11
// # 1. Redistributions of source code must retain the above copyright notice, this list of        #
12
// #    conditions and the following disclaimer.                                                   #
13
// #                                                                                               #
14
// # 2. Redistributions in binary form must reproduce the above copyright notice, this list of     #
15
// #    conditions and the following disclaimer in the documentation and/or other materials        #
16
// #    provided with the distribution.                                                            #
17
// #                                                                                               #
18
// # 3. Neither the name of the copyright holder nor the names of its contributors may be used to  #
19
// #    endorse or promote products derived from this software without specific prior written      #
20
// #    permission.                                                                                #
21
// #                                                                                               #
22
// # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS   #
23
// # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF               #
24
// # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE    #
25
// # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,     #
26
// # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE #
27
// # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED    #
28
// # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING     #
29
// # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED  #
30
// # OF THE POSSIBILITY OF SUCH DAMAGE.                                                            #
31
// # ********************************************************************************************* #
32
// # The NEORV32 Processor - https://github.com/stnolting/neorv32              (c) Stephan Nolting #
33
// #################################################################################################
34
 
35
 
36
/**********************************************************************//**
37
 * @file floating_point_test/main.c
38
 * @author Stephan Nolting
39
 * @brief Verification program for the NEORV32 'Zfinx' extension (floating-point in x registers) using pseudo-random data as input; compares results from hardware against pure-sw reference functions.
40
 **************************************************************************/
41
 
42
#include <neorv32.h>
43
#include <float.h>
44
#include <math.h>
45
#include "neorv32_zfinx_extension_intrinsics.h"
46
 
47
#ifdef NAN
48
/* NAN is supported */
49
#else
50
#warning NAN macro not supported!
51
#endif
52
#ifdef INFINITY
53
/* INFINITY is supported */
54
#else
55
#warning INFINITY macro not supported!
56
#endif
57
 
58
 
59
/**********************************************************************//**
60
 * @name User configuration
61
 **************************************************************************/
62
/**@{*/
63
/** UART BAUD rate */
64
#define BAUD_RATE          (19200)
65
//** Number of test cases for each instruction */
66
#define NUM_TEST_CASES     (1000000)
67
//** Silent mode (only show actual errors when != 0) */
68
#define SILENT_MODE        (1)
69
//** Run conversion tests when != 0 */
70
#define RUN_CONV_TESTS     (1)
71
//** Run add/sub tests when != 0 */
72
#define RUN_ADDSUB_TESTS   (1)
73
//** Run multiplication tests when != 0 */
74
#define RUN_MUL_TESTS      (1)
75
//** Run min/max tests when != 0 */
76
#define RUN_MINMAX_TESTS   (1)
77
//** Run comparison tests when != 0 */
78
#define RUN_COMPARE_TESTS  (1)
79
//** Run sign-injection tests when != 0 */
80
#define RUN_SGNINJ_TESTS   (1)
81
//** Run classify tests when != 0 */
82
#define RUN_CLASSIFY_TESTS (1)
83
//** Run unsupported instructions tests when != 0 */
84
#define RUN_UNAVAIL_TESTS  (1)
85 56 zero_gravi
//** Run average instruction execution time test when != 0 */
86
#define RUN_TIMING_TESTS   (0)
87 55 zero_gravi
/**@}*/
88
 
89
 
90
// Prototypes
91
uint32_t get_test_vector(void);
92
uint32_t xorshift32(void);
93
uint32_t verify_result(uint32_t num, uint32_t opa, uint32_t opb, uint32_t ref, uint32_t res);
94
void print_report(uint32_t num_err);
95
 
96
 
97
/**********************************************************************//**
98
 * Main function; test all available operations of the NEORV32 'Zfinx' extensions using bit floating-point hardware intrinsics and software-only reference functions (emulation).
99
 *
100
 * @note This program requires the Zfinx CPU extension.
101
 *
102 60 zero_gravi
 * @return 0 if execution was successful
103 55 zero_gravi
 **************************************************************************/
104
int main() {
105
 
106
  uint32_t err_cnt = 0;
107
  uint32_t err_cnt_total = 0;
108
  uint32_t test_cnt = 0;
109
  uint32_t i = 0;
110
  float_conv_t opa;
111
  float_conv_t opb;
112
  float_conv_t res_hw;
113
  float_conv_t res_sw;
114
 
115
 
116
  // init primary UART
117
  neorv32_uart_setup(BAUD_RATE, PARITY_NONE, FLOW_CONTROL_NONE);
118
 
119
  // capture all exceptions and give debug info via UART
120
  neorv32_rte_setup();
121
 
122
  // check available hardware extensions and compare with compiler flags
123
  neorv32_rte_check_isa(0); // silent = 0 -> show message if isa mismatch
124
 
125
  // check if Zfinx extension is implemented at all
126 60 zero_gravi
  if (neorv32_cpu_check_zext(CSR_MZEXT_ZFINX) == 0) {
127 55 zero_gravi
    neorv32_uart_print("Error! <Zfinx> extension not synthesized!\n");
128 60 zero_gravi
    return 1;
129 55 zero_gravi
  }
130
 
131
 
132
// Disable compilation by default
133 60 zero_gravi
#ifndef RUN_CHECK
134
  #warning Program HAS NOT BEEN COMPILED! Use >>make USER_FLAGS+=-DRUN_CHECK clean_all exe<< to compile it.
135 55 zero_gravi
 
136
  // inform the user if you are actually executing this
137 60 zero_gravi
  neorv32_uart_printf("ERROR! Program has not been compiled. Use >>make USER_FLAGS+=-DRUN_CHECK clean_all exe<< to compile it.\n");
138 55 zero_gravi
 
139 60 zero_gravi
  return 1;
140 55 zero_gravi
#endif
141
 
142
 
143
  // intro
144
  neorv32_uart_printf("<<< Zfinx extension test >>>\n");
145
#if (SILENT_MODE != 0)
146
  neorv32_uart_printf("SILENT_MODE enabled (only showing actual errors)\n");
147
#endif
148 56 zero_gravi
  neorv32_uart_printf("Test cases per instruction: %u\n", (uint32_t)NUM_TEST_CASES);
149
  neorv32_uart_printf("NOTE: The NEORV32 FPU does not support subnormal numbers yet. Subnormal numbers are flushed to zero.\n\n");
150 55 zero_gravi
 
151
 
152
  // clear exception status word
153
  neorv32_cpu_csr_write(CSR_FFLAGS, 0);; // real hardware
154
  feclearexcept(FE_ALL_EXCEPT); // software runtime (GCC floating-point emulation)
155
 
156
 
157
// ----------------------------------------------------------------------------
158
// Conversion Tests
159
// ----------------------------------------------------------------------------
160
 
161
#if (RUN_CONV_TESTS != 0)
162
  neorv32_uart_printf("\n#%u: FCVT.S.WU (unsigned integer to float)...\n", test_cnt);
163
  err_cnt = 0;
164
  for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) {
165
    opa.binary_value = get_test_vector();
166
    res_hw.float_value = riscv_intrinsic_fcvt_swu(opa.binary_value);
167
    res_sw.float_value = riscv_emulate_fcvt_swu(opa.binary_value);
168
    err_cnt += verify_result(i, opa.binary_value, 0, res_sw.binary_value, res_hw.binary_value);
169
  }
170
  print_report(err_cnt);
171
  err_cnt_total += err_cnt;
172
  test_cnt++;
173
 
174
  neorv32_uart_printf("\n#%u: FCVT.S.W (signed integer to float)...\n", test_cnt);
175
  err_cnt = 0;
176
  for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) {
177
    opa.binary_value = get_test_vector();
178
    res_hw.float_value = riscv_intrinsic_fcvt_sw((int32_t)opa.binary_value);
179
    res_sw.float_value = riscv_emulate_fcvt_sw((int32_t)opa.binary_value);
180
    err_cnt += verify_result(i, opa.binary_value, 0, res_sw.binary_value, res_hw.binary_value);
181
  }
182
  print_report(err_cnt);
183
  err_cnt_total += err_cnt;
184
  test_cnt++;
185
 
186
  neorv32_uart_printf("\n#%u: FCVT.WU.S (float to unsigned integer)...\n", test_cnt);
187
  err_cnt = 0;
188
  for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) {
189
    opa.binary_value = get_test_vector();
190
    res_hw.binary_value = riscv_intrinsic_fcvt_wus(opa.float_value);
191
    res_sw.binary_value = riscv_emulate_fcvt_wus(opa.float_value);
192
    err_cnt += verify_result(i, opa.binary_value, 0, res_sw.binary_value, res_hw.binary_value);
193
  }
194
  print_report(err_cnt);
195
  err_cnt_total += err_cnt;
196
  test_cnt++;
197
 
198
  neorv32_uart_printf("\n#%u: FCVT.W.S (float to signed integer)...\n", test_cnt);
199
  err_cnt = 0;
200
  for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) {
201
    opa.binary_value = get_test_vector();
202
    res_hw.binary_value = (uint32_t)riscv_intrinsic_fcvt_ws(opa.float_value);
203
    res_sw.binary_value = (uint32_t)riscv_emulate_fcvt_ws(opa.float_value);
204
    err_cnt += verify_result(i, opa.binary_value, 0, res_sw.binary_value, res_hw.binary_value);
205
  }
206
  print_report(err_cnt);
207
  err_cnt_total += err_cnt;
208
  test_cnt++;
209
#endif
210
 
211
 
212
// ----------------------------------------------------------------------------
213
// Add/Sub Tests
214
// ----------------------------------------------------------------------------
215
 
216
#if (RUN_ADDSUB_TESTS != 0)
217
  neorv32_uart_printf("\n#%u: FADD.S (addition)...\n", test_cnt);
218
  err_cnt = 0;
219
  for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) {
220
    opa.binary_value = get_test_vector();
221
    opb.binary_value = get_test_vector();
222
    res_hw.float_value = riscv_intrinsic_fadds(opa.float_value, opb.float_value);
223
    res_sw.float_value = riscv_emulate_fadds(opa.float_value, opb.float_value);
224
    err_cnt += verify_result(i, opa.binary_value, opb.binary_value, res_sw.binary_value, res_hw.binary_value);
225
  }
226
  print_report(err_cnt);
227
  err_cnt_total += err_cnt;
228
  test_cnt++;
229
 
230
  neorv32_uart_printf("\n#%u: FSUB.S (subtraction)...\n", test_cnt);
231
  err_cnt = 0;
232
  for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) {
233
    opa.binary_value = get_test_vector();
234
    opb.binary_value = get_test_vector();
235
    res_hw.float_value = riscv_intrinsic_fsubs(opa.float_value, opb.float_value);
236
    res_sw.float_value = riscv_emulate_fsubs(opa.float_value, opb.float_value);
237
    err_cnt += verify_result(i, opa.binary_value, opb.binary_value, res_sw.binary_value, res_hw.binary_value);
238
  }
239
  print_report(err_cnt);
240
  err_cnt_total += err_cnt;
241
  test_cnt++;
242
#endif
243
 
244
 
245
// ----------------------------------------------------------------------------
246
// Multiplication Tests
247
// ----------------------------------------------------------------------------
248
 
249
#if (RUN_MUL_TESTS != 0)
250
  neorv32_uart_printf("\n#%u: FMUL.S (multiplication)...\n", test_cnt);
251
  err_cnt = 0;
252
  for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) {
253
    opa.binary_value = get_test_vector();
254
    opb.binary_value = get_test_vector();
255
    res_hw.float_value = riscv_intrinsic_fmuls(opa.float_value, opb.float_value);
256
    res_sw.float_value = riscv_emulate_fmuls(opa.float_value, opb.float_value);
257
    err_cnt += verify_result(i, opa.binary_value, opb.binary_value, res_sw.binary_value, res_hw.binary_value);
258
  }
259
  print_report(err_cnt);
260
  err_cnt_total += err_cnt;
261
  test_cnt++;
262
#endif
263
 
264
 
265
// ----------------------------------------------------------------------------
266
// Min/Max Tests
267
// ----------------------------------------------------------------------------
268
 
269
#if (RUN_MINMAX_TESTS != 0)
270
  neorv32_uart_printf("\n#%u: FMIN.S (select minimum)...\n", test_cnt);
271
  err_cnt = 0;
272
  for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) {
273
    opa.binary_value = get_test_vector();
274
    opb.binary_value = get_test_vector();
275
    res_hw.float_value = riscv_intrinsic_fmins(opa.float_value, opb.float_value);
276
    res_sw.float_value = riscv_emulate_fmins(opa.float_value, opb.float_value);
277
    err_cnt += verify_result(i, opa.binary_value, opb.binary_value, res_sw.binary_value, res_hw.binary_value);
278
  }
279
  print_report(err_cnt);
280
  err_cnt_total += err_cnt;
281
  test_cnt++;
282
 
283
  neorv32_uart_printf("\n#%u: FMAX.S (select maximum)...\n", test_cnt);
284
  err_cnt = 0;
285
  for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) {
286
    opa.binary_value = get_test_vector();
287
    opb.binary_value = get_test_vector();
288
    res_hw.float_value = riscv_intrinsic_fmaxs(opa.float_value, opb.float_value);
289
    res_sw.float_value = riscv_emulate_fmaxs(opa.float_value, opb.float_value);
290
    err_cnt += verify_result(i, opa.binary_value, opb.binary_value, res_sw.binary_value, res_hw.binary_value);
291
  }
292
  print_report(err_cnt);
293
  err_cnt_total += err_cnt;
294
  test_cnt++;
295
#endif
296
 
297
 
298
// ----------------------------------------------------------------------------
299
// Comparison Tests
300
// ----------------------------------------------------------------------------
301
 
302
#if (RUN_COMPARE_TESTS != 0)
303
  neorv32_uart_printf("\n#%u: FEQ.S (compare if equal)...\n", test_cnt);
304
  err_cnt = 0;
305
  for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) {
306
    opa.binary_value = get_test_vector();
307
    opb.binary_value = get_test_vector();
308
    res_hw.binary_value = riscv_intrinsic_feqs(opa.float_value, opb.float_value);
309
    res_sw.binary_value = riscv_emulate_feqs(opa.float_value, opb.float_value);
310
    err_cnt += verify_result(i, opa.binary_value, opb.binary_value, res_sw.binary_value, res_hw.binary_value);
311
  }
312
  print_report(err_cnt);
313
  err_cnt_total += err_cnt;
314
  test_cnt++;
315
 
316
  neorv32_uart_printf("\n#%u: FLT.S (compare if less-than)...\n", test_cnt);
317
  err_cnt = 0;
318
  for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) {
319
    opa.binary_value = get_test_vector();
320
    opb.binary_value = get_test_vector();
321
    res_hw.binary_value = riscv_intrinsic_flts(opa.float_value, opb.float_value);
322
    res_sw.binary_value = riscv_emulate_flts(opa.float_value, opb.float_value);
323
    err_cnt += verify_result(i, opa.binary_value, opb.binary_value, res_sw.binary_value, res_hw.binary_value);
324
  }
325
  print_report(err_cnt);
326
  err_cnt_total += err_cnt;
327
  test_cnt++;
328
 
329
  neorv32_uart_printf("\n#%u: FLE.S (compare if less-than-or-equal)...\n", test_cnt);
330
  err_cnt = 0;
331
  for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) {
332
    opa.binary_value = get_test_vector();
333
    opb.binary_value = get_test_vector();
334
    res_hw.binary_value = riscv_intrinsic_fles(opa.float_value, opb.float_value);
335
    res_sw.binary_value = riscv_emulate_fles(opa.float_value, opb.float_value);
336
    err_cnt += verify_result(i, opa.binary_value, opb.binary_value, res_sw.binary_value, res_hw.binary_value);
337
  }
338
  print_report(err_cnt);
339
  err_cnt_total += err_cnt;
340
  test_cnt++;
341
#endif
342
 
343
 
344
// ----------------------------------------------------------------------------
345
// Sign-Injection Tests
346
// ----------------------------------------------------------------------------
347
 
348
#if (RUN_SGNINJ_TESTS != 0)
349
  neorv32_uart_printf("\n#%u: FSGNJ.S (sign-injection)...\n", test_cnt);
350
  err_cnt = 0;
351
  for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) {
352
    opa.binary_value = get_test_vector();
353
    opb.binary_value = get_test_vector();
354
    res_hw.float_value = riscv_intrinsic_fsgnjs(opa.float_value, opb.float_value);
355
    res_sw.float_value = riscv_emulate_fsgnjs(opa.float_value, opb.float_value);
356
    err_cnt += verify_result(i, opa.binary_value, opb.binary_value, res_sw.binary_value, res_hw.binary_value);
357
  }
358
  print_report(err_cnt);
359
  err_cnt_total += err_cnt;
360
  test_cnt++;
361
 
362
  neorv32_uart_printf("\n#%u: FSGNJN.S (sign-injection NOT)...\n", test_cnt);
363
  err_cnt = 0;
364
  for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) {
365
    opa.binary_value = get_test_vector();
366
    opb.binary_value = get_test_vector();
367
    res_hw.float_value = riscv_intrinsic_fsgnjns(opa.float_value, opb.float_value);
368
    res_sw.float_value = riscv_emulate_fsgnjns(opa.float_value, opb.float_value);
369
    err_cnt += verify_result(i, opa.binary_value, opb.binary_value, res_sw.binary_value, res_hw.binary_value);
370
  }
371
  print_report(err_cnt);
372
  err_cnt_total += err_cnt;
373
  test_cnt++;
374
 
375
  neorv32_uart_printf("\n#%u: FSGNJX.S (sign-injection XOR)...\n", test_cnt);
376
  err_cnt = 0;
377
  for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) {
378
    opa.binary_value = get_test_vector();
379
    opb.binary_value = get_test_vector();
380
    res_hw.float_value = riscv_intrinsic_fsgnjxs(opa.float_value, opb.float_value);
381
    res_sw.float_value = riscv_emulate_fsgnjxs(opa.float_value, opb.float_value);
382
    err_cnt += verify_result(i, opa.binary_value, opb.binary_value, res_sw.binary_value, res_hw.binary_value);
383
  }
384
  print_report(err_cnt);
385
  err_cnt_total += err_cnt;
386
  test_cnt++;
387
#endif
388
 
389
 
390
// ----------------------------------------------------------------------------
391
// Classify Tests
392
// ----------------------------------------------------------------------------
393
 
394
#if (RUN_CLASSIFY_TESTS != 0)
395
  neorv32_uart_printf("\n#%u: FCLASS.S (classify)...\n", test_cnt);
396
  err_cnt = 0;
397
  for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) {
398
    opa.binary_value = get_test_vector();
399
    res_hw.binary_value = riscv_intrinsic_fclasss(opa.float_value);
400
    res_sw.binary_value = riscv_emulate_fclasss(opa.float_value);
401
    err_cnt += verify_result(i, opa.binary_value, 0, res_sw.binary_value, res_hw.binary_value);
402
  }
403
  print_report(err_cnt);
404
  err_cnt_total += err_cnt;
405
  test_cnt++;
406
#endif
407
 
408
 
409
// ----------------------------------------------------------------------------
410
// UNSUPPORTED Instructions Tests - Execution should raise illegal instruction exception
411
// ----------------------------------------------------------------------------
412
 
413
#if (RUN_UNAVAIL_TESTS != 0)
414
  neorv32_uart_printf("\n# unsupported FDIV.S (division) [illegal instruction]...\n");
415
  neorv32_cpu_csr_write(CSR_MCAUSE, 0);
416
  opa.binary_value = get_test_vector();
417
  opb.binary_value = get_test_vector();
418
  riscv_intrinsic_fdivs(opa.float_value, opb.float_value);
419 56 zero_gravi
  if (neorv32_cpu_csr_read(CSR_MCAUSE) != TRAP_CODE_I_ILLEGAL) {
420 55 zero_gravi
    neorv32_uart_printf("%c[1m[FAILED]%c[0m\n", 27, 27);
421
    err_cnt_total++;
422
  }
423
  else {
424
    neorv32_uart_printf("%c[1m[ok]%c[0m\n", 27, 27);
425
  }
426
 
427
  neorv32_uart_printf("\n# unsupported FSQRT.S (square root) [illegal instruction]...\n");
428
  neorv32_cpu_csr_write(CSR_MCAUSE, 0);
429
  opa.binary_value = get_test_vector();
430
  opb.binary_value = get_test_vector();
431
  riscv_intrinsic_fsqrts(opa.float_value);
432 56 zero_gravi
  if (neorv32_cpu_csr_read(CSR_MCAUSE) != TRAP_CODE_I_ILLEGAL) {
433 55 zero_gravi
    neorv32_uart_printf("%c[1m[FAILED]%c[0m\n", 27, 27);
434
    err_cnt_total++;
435
  }
436
  else {
437
    neorv32_uart_printf("%c[1m[ok]%c[0m\n", 27, 27);
438
  }
439
 
440
  neorv32_uart_printf("\n# unsupported FMADD.S (fused multiply-add) [illegal instruction]...\n");
441
  neorv32_cpu_csr_write(CSR_MCAUSE, 0);
442
  opa.binary_value = get_test_vector();
443
  opb.binary_value = get_test_vector();
444
  riscv_intrinsic_fmadds(opa.float_value, opb.float_value, -opa.float_value);
445 56 zero_gravi
  if (neorv32_cpu_csr_read(CSR_MCAUSE) != TRAP_CODE_I_ILLEGAL) {
446 55 zero_gravi
    neorv32_uart_printf("%c[1m[FAILED]%c[0m\n", 27, 27);
447
    err_cnt_total++;
448
  }
449
  else {
450
    neorv32_uart_printf("%c[1m[ok]%c[0m\n", 27, 27);
451
  }
452
 
453
  neorv32_uart_printf("\n# unsupported FMSUB.S (fused multiply-sub) [illegal instruction]...\n");
454
  neorv32_cpu_csr_write(CSR_MCAUSE, 0);
455
  opa.binary_value = get_test_vector();
456
  opb.binary_value = get_test_vector();
457
  riscv_intrinsic_fmsubs(opa.float_value, opb.float_value, -opa.float_value);
458 56 zero_gravi
  if (neorv32_cpu_csr_read(CSR_MCAUSE) != TRAP_CODE_I_ILLEGAL) {
459 55 zero_gravi
    neorv32_uart_printf("%c[1m[FAILED]%c[0m\n", 27, 27);
460
    err_cnt_total++;
461
  }
462
  else {
463
    neorv32_uart_printf("%c[1m[ok]%c[0m\n", 27, 27);
464
  }
465
 
466
  neorv32_uart_printf("\n# unsupported FNMSUB.S (fused negated multiply-sub) [illegal instruction]...\n");
467
  neorv32_cpu_csr_write(CSR_MCAUSE, 0);
468
  opa.binary_value = get_test_vector();
469
  opb.binary_value = get_test_vector();
470
  riscv_intrinsic_fnmadds(opa.float_value, opb.float_value, -opa.float_value);
471 56 zero_gravi
  if (neorv32_cpu_csr_read(CSR_MCAUSE) != TRAP_CODE_I_ILLEGAL) {
472 55 zero_gravi
    neorv32_uart_printf("%c[1m[FAILED]%c[0m\n", 27, 27);
473
    err_cnt_total++;
474
  }
475
  else {
476
    neorv32_uart_printf("%c[1m[ok]%c[0m\n", 27, 27);
477
  }
478
 
479
  neorv32_uart_printf("\n# unsupported FNMADD.S (fused negated multiply-add) [illegal instruction]...\n");
480
  neorv32_cpu_csr_write(CSR_MCAUSE, 0);
481
  opa.binary_value = get_test_vector();
482
  opb.binary_value = get_test_vector();
483
  riscv_intrinsic_fnmadds(opa.float_value, opb.float_value, -opa.float_value);
484 56 zero_gravi
  if (neorv32_cpu_csr_read(CSR_MCAUSE) != TRAP_CODE_I_ILLEGAL) {
485 55 zero_gravi
    neorv32_uart_printf("%c[1m[FAILED]%c[0m\n", 27, 27);
486
    err_cnt_total++;
487
  }
488
  else {
489
    neorv32_uart_printf("%c[1m[ok]%c[0m\n", 27, 27);
490
  }
491
#endif
492
 
493
 
494 56 zero_gravi
// ----------------------------------------------------------------------------
495
// Instruction execution timing test
496
// ----------------------------------------------------------------------------
497
 
498
#if (RUN_TIMING_TESTS != 0)
499
 
500
  uint32_t time_start, time_sw, time_hw;
501
  const uint32_t num_runs = 4096;
502
 
503
  neorv32_uart_printf("\nAverage execution time tests (%u runs)\n", num_runs);
504
 
505
 
506
  // signed integer to float
507
  neorv32_uart_printf("FCVT.S.W: ");
508
  time_sw = 0;
509
  time_hw = 0;
510
  err_cnt = 0;
511
  for (i=0; i<num_runs; i++) {
512
    opa.binary_value = get_test_vector();
513
 
514
    // hardware execution time
515
    time_start = neorv32_cpu_csr_read(CSR_CYCLE);
516
    {
517
      res_hw.float_value = riscv_intrinsic_fcvt_sw((int32_t)opa.binary_value);
518
    }
519
    time_hw += neorv32_cpu_csr_read(CSR_CYCLE) - time_start;
520
    time_hw -= 4; // remove the 2 dummy instructions
521
 
522
    // software (emulation) execution time
523
    time_start = neorv32_cpu_csr_read(CSR_CYCLE);
524
    {
525
      res_sw.float_value = riscv_emulate_fcvt_sw((int32_t)opa.binary_value);
526
    }
527
    time_sw += neorv32_cpu_csr_read(CSR_CYCLE) - time_start;
528
 
529
    if (res_sw.binary_value != res_hw.binary_value) {
530
      err_cnt++;
531
    }
532
  }
533
 
534
  if (err_cnt == 0) {
535
    neorv32_uart_printf("cycles[SW] = %u vs. cycles[HW] = %u\n", time_sw/num_runs, time_hw/num_runs);
536
  }
537
  else {
538
    neorv32_uart_printf("%c[1m[TEST FAILED!]%c[0m\n", 27, 27);
539
    err_cnt_total++;
540
  }
541
 
542
 
543
  // float to signed integer
544
  neorv32_uart_printf("FCVT.W.S: ");
545
  time_sw = 0;
546
  time_hw = 0;
547
  err_cnt = 0;
548
  for (i=0; i<num_runs; i++) {
549
    opa.binary_value = get_test_vector();
550
 
551
    // hardware execution time
552
    time_start = neorv32_cpu_csr_read(CSR_CYCLE);
553
    {
554
      res_hw.binary_value = (uint32_t)riscv_intrinsic_fcvt_ws(opa.float_value);
555
    }
556
    time_hw += neorv32_cpu_csr_read(CSR_CYCLE) - time_start;
557
    time_hw -= 4; // remove the 2 dummy instructions
558
 
559
    // software (emulation) execution time
560
    time_start = neorv32_cpu_csr_read(CSR_CYCLE);
561
    {
562
      res_sw.binary_value = (uint32_t)riscv_emulate_fcvt_ws(opa.float_value);
563
    }
564
    time_sw += neorv32_cpu_csr_read(CSR_CYCLE) - time_start;
565
 
566
    if (res_sw.binary_value != res_hw.binary_value) {
567
      err_cnt++;
568
    }
569
  }
570
 
571
  if (err_cnt == 0) {
572
    neorv32_uart_printf("cycles[SW] = %u vs. cycles[HW] = %u\n", time_sw/num_runs, time_hw/num_runs);
573
  }
574
  else {
575
    neorv32_uart_printf("%c[1m[TEST FAILED!]%c[0m\n", 27, 27);
576
    err_cnt_total++;
577
  }
578
 
579
 
580
  // addition
581
  neorv32_uart_printf("FADD.S:   ");
582
  time_sw = 0;
583
  time_hw = 0;
584
  err_cnt = 0;
585
  for (i=0; i<num_runs; i++) {
586
    opa.binary_value = get_test_vector();
587
    opb.binary_value = get_test_vector();
588
 
589
    // hardware execution time
590
    time_start = neorv32_cpu_csr_read(CSR_CYCLE);
591
    {
592
      res_hw.float_value = riscv_intrinsic_fadds(opa.float_value, opb.float_value);
593
    }
594
    time_hw += neorv32_cpu_csr_read(CSR_CYCLE) - time_start;
595
    time_hw -= 4; // remove the 2 dummy instructions
596
 
597
    // software (emulation) execution time
598
    time_start = neorv32_cpu_csr_read(CSR_CYCLE);
599
    {
600
      res_sw.float_value = riscv_emulate_fadds(opa.float_value, opb.float_value);
601
    }
602
    time_sw += neorv32_cpu_csr_read(CSR_CYCLE) - time_start;
603
 
604
    if (res_sw.binary_value != res_hw.binary_value) {
605
      err_cnt++;
606
    }
607
  }
608
 
609
  if (err_cnt == 0) {
610
    neorv32_uart_printf("cycles[SW] = %u vs. cycles[HW] = %u\n", time_sw/num_runs, time_hw/num_runs);
611
  }
612
  else {
613
    neorv32_uart_printf("%c[1m[TEST FAILED!]%c[0m\n", 27, 27);
614
    err_cnt_total++;
615
  }
616
 
617
 
618
  // subtraction
619
  neorv32_uart_printf("FSUB.S:   ");
620
  time_sw = 0;
621
  time_hw = 0;
622
  err_cnt = 0;
623
  for (i=0; i<num_runs; i++) {
624
    opa.binary_value = get_test_vector();
625
    opb.binary_value = get_test_vector();
626
 
627
    // hardware execution time
628
    time_start = neorv32_cpu_csr_read(CSR_CYCLE);
629
    {
630
      res_hw.float_value = riscv_intrinsic_fsubs(opa.float_value, opb.float_value);
631
    }
632
    time_hw += neorv32_cpu_csr_read(CSR_CYCLE) - time_start;
633
    time_hw -= 4; // remove the 2 dummy instructions
634
 
635
    // software (emulation) execution time
636
    time_start = neorv32_cpu_csr_read(CSR_CYCLE);
637
    {
638
      res_sw.float_value = riscv_emulate_fsubs(opa.float_value, opb.float_value);
639
    }
640
    time_sw += neorv32_cpu_csr_read(CSR_CYCLE) - time_start;
641
 
642
    if (res_sw.binary_value != res_hw.binary_value) {
643
      err_cnt++;
644
    }
645
  }
646
 
647
  if (err_cnt == 0) {
648
    neorv32_uart_printf("cycles[SW] = %u vs. cycles[HW] = %u\n", time_sw/num_runs, time_hw/num_runs);
649
  }
650
  else {
651
    neorv32_uart_printf("%c[1m[TEST FAILED!]%c[0m\n", 27, 27);
652
    err_cnt_total++;
653
  }
654
 
655
 
656
  // multiplication
657
  neorv32_uart_printf("FMUL.S:   ");
658
  time_sw = 0;
659
  time_hw = 0;
660
  err_cnt = 0;
661
  for (i=0; i<num_runs; i++) {
662
    opa.binary_value = get_test_vector();
663
    opb.binary_value = get_test_vector();
664
 
665
    // hardware execution time
666
    time_start = neorv32_cpu_csr_read(CSR_CYCLE);
667
    {
668
      res_hw.float_value = riscv_intrinsic_fmuls(opa.float_value, opb.float_value);
669
    }
670
    time_hw += neorv32_cpu_csr_read(CSR_CYCLE) - time_start;
671
    time_hw -= 4; // remove the 2 dummy instructions
672
 
673
    // software (emulation) execution time
674
    time_start = neorv32_cpu_csr_read(CSR_CYCLE);
675
    {
676
      res_sw.float_value = riscv_emulate_fmuls(opa.float_value, opb.float_value);
677
    }
678
    time_sw += neorv32_cpu_csr_read(CSR_CYCLE) - time_start;
679
 
680
    if (res_sw.binary_value != res_hw.binary_value) {
681
      err_cnt++;
682
    }
683
  }
684
 
685
  if (err_cnt == 0) {
686
    neorv32_uart_printf("cycles[SW] = %u vs. cycles[HW] = %u\n", time_sw/num_runs, time_hw/num_runs);
687
  }
688
  else {
689
    neorv32_uart_printf("%c[1m[TEST FAILED!]%c[0m\n", 27, 27);
690
    err_cnt_total++;
691
  }
692
 
693
 
694
  // Max
695
  neorv32_uart_printf("FMAX.S:   ");
696
  time_sw = 0;
697
  time_hw = 0;
698
  err_cnt = 0;
699
  for (i=0; i<num_runs; i++) {
700
    opa.binary_value = get_test_vector();
701
    opb.binary_value = get_test_vector();
702
 
703
    // hardware execution time
704
    time_start = neorv32_cpu_csr_read(CSR_CYCLE);
705
    {
706
      res_hw.float_value = riscv_intrinsic_fmaxs(opa.float_value, opb.float_value);
707
    }
708
    time_hw += neorv32_cpu_csr_read(CSR_CYCLE) - time_start;
709
    time_hw -= 4; // remove the 2 dummy instructions
710
 
711
    // software (emulation) execution time
712
    time_start = neorv32_cpu_csr_read(CSR_CYCLE);
713
    {
714
      res_sw.float_value = riscv_emulate_fmaxs(opa.float_value, opb.float_value);
715
    }
716
    time_sw += neorv32_cpu_csr_read(CSR_CYCLE) - time_start;
717
 
718
    if (res_sw.binary_value != res_hw.binary_value) {
719
      err_cnt++;
720
    }
721
  }
722
 
723
  if (err_cnt == 0) {
724
    neorv32_uart_printf("cycles[SW] = %u vs. cycles[HW] = %u\n", time_sw/num_runs, time_hw/num_runs);
725
  }
726
  else {
727
    neorv32_uart_printf("%c[1m[TEST FAILED!]%c[0m\n", 27, 27);
728
    err_cnt_total++;
729
  }
730
 
731
 
732
  // Comparison
733
  neorv32_uart_printf("FLE.S:    ");
734
  time_sw = 0;
735
  time_hw = 0;
736
  err_cnt = 0;
737
  for (i=0; i<num_runs; i++) {
738
    opa.binary_value = get_test_vector();
739
    opb.binary_value = get_test_vector();
740
 
741
    // hardware execution time
742
    time_start = neorv32_cpu_csr_read(CSR_CYCLE);
743
    {
744
      res_hw.float_value = riscv_intrinsic_fles(opa.float_value, opb.float_value);
745
    }
746
    time_hw += neorv32_cpu_csr_read(CSR_CYCLE) - time_start;
747
    time_hw -= 4; // remove the 2 dummy instructions
748
 
749
    // software (emulation) execution time
750
    time_start = neorv32_cpu_csr_read(CSR_CYCLE);
751
    {
752
      res_sw.float_value = riscv_emulate_fles(opa.float_value, opb.float_value);
753
    }
754
    time_sw += neorv32_cpu_csr_read(CSR_CYCLE) - time_start;
755
 
756
    if (res_sw.binary_value != res_hw.binary_value) {
757
      err_cnt++;
758
    }
759
  }
760
 
761
  if (err_cnt == 0) {
762
    neorv32_uart_printf("cycles[SW] = %u vs. cycles[HW] = %u\n", time_sw/num_runs, time_hw/num_runs);
763
  }
764
  else {
765
    neorv32_uart_printf("%c[1m[TEST FAILED!]%c[0m\n", 27, 27);
766
    err_cnt_total++;
767
  }
768
 
769
 
770
  // Sign-injection
771
  neorv32_uart_printf("FSGNJX.S: ");
772
  time_sw = 0;
773
  time_hw = 0;
774
  err_cnt = 0;
775
  for (i=0; i<num_runs; i++) {
776
    opa.binary_value = get_test_vector();
777
    opb.binary_value = get_test_vector();
778
 
779
    // hardware execution time
780
    time_start = neorv32_cpu_csr_read(CSR_CYCLE);
781
    {
782
      res_hw.float_value = riscv_intrinsic_fsgnjxs(opa.float_value, opb.float_value);
783
    }
784
    time_hw += neorv32_cpu_csr_read(CSR_CYCLE) - time_start;
785
    time_hw -= 4; // remove the 2 dummy instructions
786
 
787
    // software (emulation) execution time
788
    time_start = neorv32_cpu_csr_read(CSR_CYCLE);
789
    {
790
      res_sw.float_value = riscv_emulate_fsgnjxs(opa.float_value, opb.float_value);
791
    }
792
    time_sw += neorv32_cpu_csr_read(CSR_CYCLE) - time_start;
793
 
794
    if (res_sw.binary_value != res_hw.binary_value) {
795
      err_cnt++;
796
    }
797
  }
798
 
799
  if (err_cnt == 0) {
800
    neorv32_uart_printf("cycles[SW] = %u vs. cycles[HW] = %u\n", time_sw/num_runs, time_hw/num_runs);
801
  }
802
  else {
803
    neorv32_uart_printf("%c[1m[TEST FAILED!]%c[0m\n", 27, 27);
804
    err_cnt_total++;
805
  }
806
#endif
807
 
808
 
809
// ----------------------------------------------------------------------------
810
// Final report
811
// ----------------------------------------------------------------------------
812
 
813 55 zero_gravi
  if (err_cnt_total != 0) {
814
    neorv32_uart_printf("\n%c[1m[ZFINX EXTENSION VERIFICATION FAILED!]%c[0m\n", 27, 27);
815
    neorv32_uart_printf("%u errors in %u test cases\n", err_cnt_total, test_cnt*(uint32_t)NUM_TEST_CASES);
816 60 zero_gravi
    return 1;
817 55 zero_gravi
  }
818
  else {
819
    neorv32_uart_printf("\n%c[1m[Zfinx extension verification successful!]%c[0m\n", 27, 27);
820 60 zero_gravi
    return 0;
821 55 zero_gravi
  }
822
 
823
}
824
 
825
 
826
/**********************************************************************//**
827
 * Generate 32-bit test data (including special values like INFINITY every now and then).
828
 *
829
 * @return Test data (32-bit).
830
 **************************************************************************/
831
uint32_t get_test_vector(void) {
832
 
833
  float_conv_t tmp;
834
 
835
  // generate special value "every" ~256th time this function is called
836
  if ((xorshift32() & 0xff) == 0xff) {
837
 
838
    switch((xorshift32() >> 10) & 0x3) { // random decision which special value we are taking
839
      case  0: tmp.float_value  = +INFINITY; break;
840
      case  1: tmp.float_value  = -INFINITY; break;
841
      case  2: tmp.float_value  = +0.0f; break;
842
      case  3: tmp.float_value  = -0.0f; break;
843
      case  4: tmp.binary_value = 0x7fffffff; break;
844
      case  5: tmp.binary_value = 0xffffffff; break;
845
      case  6: tmp.float_value  = NAN; break;
846
      case  7: tmp.float_value  = NAN; break; // FIXME signaling_NAN?
847
      default: tmp.float_value  = NAN; break;
848
    }
849
  }
850
  else {
851
    tmp.binary_value = xorshift32();
852
  }
853
 
854
  return tmp.binary_value;
855
}
856
 
857
 
858
/**********************************************************************//**
859
 * PSEUDO-RANDOM number generator.
860
 *
861
 * @return Random data (32-bit).
862
 **************************************************************************/
863
uint32_t xorshift32(void) {
864
 
865
  static uint32_t x32 = 314159265;
866
 
867
  x32 ^= x32 << 13;
868
  x32 ^= x32 >> 17;
869
  x32 ^= x32 << 5;
870
 
871
  return x32;
872
}
873
 
874
 
875
/**********************************************************************//**
876
 * Verify results (software reference vs. actual hardware).
877
 *
878
 * @param[in] num Test case number
879
 * @param[in] opa Operand 1
880
 * @param[in] opb Operand 2
881
 * @param[in] ref Software reference
882
 * @param[in] res Actual results from hardware
883
 * @return zero if results are equal.
884
 **************************************************************************/
885
uint32_t verify_result(uint32_t num, uint32_t opa, uint32_t opb, uint32_t ref, uint32_t res) {
886
 
887
#if (SILENT_MODE == 0)
888
  neorv32_uart_printf("%u: opa = 0x%x, opb = 0x%x : ref[SW] = 0x%x vs. res[HW] = 0x%x ", num, opa, opb, ref, res);
889
#endif
890
 
891
  if (ref != res) {
892
#if (SILENT_MODE != 0)
893
    neorv32_uart_printf("%u: opa = 0x%x, opb = 0x%x : ref[SW] = 0x%x vs. res[HW] = 0x%x ", num, opa, opb, ref, res);
894
#endif
895
    neorv32_uart_printf("%c[1m[FAILED]%c[0m\n", 27, 27);
896
    return 1;
897
  }
898
  else {
899
#if (SILENT_MODE == 0)
900
    neorv32_uart_printf("%c[1m[ok]%c[0m\n", 27, 27);
901
#endif
902
    return 0;
903
  }
904
}
905
 
906
 
907
/**********************************************************************//**
908
 * Print test report.
909
 *
910
 * @param[in] num_err Number or errors in this test.
911
 **************************************************************************/
912
void print_report(uint32_t num_err) {
913
 
914
  neorv32_uart_printf("Errors: %u/%u ", num_err, (uint32_t)NUM_TEST_CASES);
915
 
916
  if (num_err == 0) {
917
    neorv32_uart_printf("%c[1m[ok]%c[0m\n", 27, 27);
918
  }
919
  else {
920
    neorv32_uart_printf("%c[1m[FAILED]%c[0m\n", 27, 27);
921
  }
922
}

powered by: WebSVN 2.1.0

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