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 62

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 62 zero_gravi
  // enable FPU extension
152
  uint32_t mstatus = neorv32_cpu_csr_read(CSR_MSTATUS);
153
  mstatus |= 1 << CSR_MSTATUS_FS_L; // state = initial
154
  neorv32_cpu_csr_write(CSR_MSTATUS, mstatus);
155 55 zero_gravi
 
156
  // clear exception status word
157 62 zero_gravi
  neorv32_cpu_csr_write(CSR_FFLAGS, 0); // real hardware
158 55 zero_gravi
  feclearexcept(FE_ALL_EXCEPT); // software runtime (GCC floating-point emulation)
159
 
160
 
161
// ----------------------------------------------------------------------------
162
// Conversion Tests
163
// ----------------------------------------------------------------------------
164
 
165
#if (RUN_CONV_TESTS != 0)
166
  neorv32_uart_printf("\n#%u: FCVT.S.WU (unsigned integer to float)...\n", test_cnt);
167
  err_cnt = 0;
168
  for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) {
169
    opa.binary_value = get_test_vector();
170
    res_hw.float_value = riscv_intrinsic_fcvt_swu(opa.binary_value);
171
    res_sw.float_value = riscv_emulate_fcvt_swu(opa.binary_value);
172
    err_cnt += verify_result(i, opa.binary_value, 0, res_sw.binary_value, res_hw.binary_value);
173
  }
174
  print_report(err_cnt);
175
  err_cnt_total += err_cnt;
176
  test_cnt++;
177
 
178
  neorv32_uart_printf("\n#%u: FCVT.S.W (signed integer to float)...\n", test_cnt);
179
  err_cnt = 0;
180
  for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) {
181
    opa.binary_value = get_test_vector();
182
    res_hw.float_value = riscv_intrinsic_fcvt_sw((int32_t)opa.binary_value);
183
    res_sw.float_value = riscv_emulate_fcvt_sw((int32_t)opa.binary_value);
184
    err_cnt += verify_result(i, opa.binary_value, 0, res_sw.binary_value, res_hw.binary_value);
185
  }
186
  print_report(err_cnt);
187
  err_cnt_total += err_cnt;
188
  test_cnt++;
189
 
190
  neorv32_uart_printf("\n#%u: FCVT.WU.S (float to unsigned integer)...\n", test_cnt);
191
  err_cnt = 0;
192
  for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) {
193
    opa.binary_value = get_test_vector();
194
    res_hw.binary_value = riscv_intrinsic_fcvt_wus(opa.float_value);
195
    res_sw.binary_value = riscv_emulate_fcvt_wus(opa.float_value);
196
    err_cnt += verify_result(i, opa.binary_value, 0, res_sw.binary_value, res_hw.binary_value);
197
  }
198
  print_report(err_cnt);
199
  err_cnt_total += err_cnt;
200
  test_cnt++;
201
 
202
  neorv32_uart_printf("\n#%u: FCVT.W.S (float to signed integer)...\n", test_cnt);
203
  err_cnt = 0;
204
  for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) {
205
    opa.binary_value = get_test_vector();
206
    res_hw.binary_value = (uint32_t)riscv_intrinsic_fcvt_ws(opa.float_value);
207
    res_sw.binary_value = (uint32_t)riscv_emulate_fcvt_ws(opa.float_value);
208
    err_cnt += verify_result(i, opa.binary_value, 0, res_sw.binary_value, res_hw.binary_value);
209
  }
210
  print_report(err_cnt);
211
  err_cnt_total += err_cnt;
212
  test_cnt++;
213
#endif
214
 
215
 
216
// ----------------------------------------------------------------------------
217
// Add/Sub Tests
218
// ----------------------------------------------------------------------------
219
 
220
#if (RUN_ADDSUB_TESTS != 0)
221
  neorv32_uart_printf("\n#%u: FADD.S (addition)...\n", test_cnt);
222
  err_cnt = 0;
223
  for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) {
224
    opa.binary_value = get_test_vector();
225
    opb.binary_value = get_test_vector();
226
    res_hw.float_value = riscv_intrinsic_fadds(opa.float_value, opb.float_value);
227
    res_sw.float_value = riscv_emulate_fadds(opa.float_value, opb.float_value);
228
    err_cnt += verify_result(i, opa.binary_value, opb.binary_value, res_sw.binary_value, res_hw.binary_value);
229
  }
230
  print_report(err_cnt);
231
  err_cnt_total += err_cnt;
232
  test_cnt++;
233
 
234
  neorv32_uart_printf("\n#%u: FSUB.S (subtraction)...\n", test_cnt);
235
  err_cnt = 0;
236
  for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) {
237
    opa.binary_value = get_test_vector();
238
    opb.binary_value = get_test_vector();
239
    res_hw.float_value = riscv_intrinsic_fsubs(opa.float_value, opb.float_value);
240
    res_sw.float_value = riscv_emulate_fsubs(opa.float_value, opb.float_value);
241
    err_cnt += verify_result(i, opa.binary_value, opb.binary_value, res_sw.binary_value, res_hw.binary_value);
242
  }
243
  print_report(err_cnt);
244
  err_cnt_total += err_cnt;
245
  test_cnt++;
246
#endif
247
 
248
 
249
// ----------------------------------------------------------------------------
250
// Multiplication Tests
251
// ----------------------------------------------------------------------------
252
 
253
#if (RUN_MUL_TESTS != 0)
254
  neorv32_uart_printf("\n#%u: FMUL.S (multiplication)...\n", test_cnt);
255
  err_cnt = 0;
256
  for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) {
257
    opa.binary_value = get_test_vector();
258
    opb.binary_value = get_test_vector();
259
    res_hw.float_value = riscv_intrinsic_fmuls(opa.float_value, opb.float_value);
260
    res_sw.float_value = riscv_emulate_fmuls(opa.float_value, opb.float_value);
261
    err_cnt += verify_result(i, opa.binary_value, opb.binary_value, res_sw.binary_value, res_hw.binary_value);
262
  }
263
  print_report(err_cnt);
264
  err_cnt_total += err_cnt;
265
  test_cnt++;
266
#endif
267
 
268
 
269
// ----------------------------------------------------------------------------
270
// Min/Max Tests
271
// ----------------------------------------------------------------------------
272
 
273
#if (RUN_MINMAX_TESTS != 0)
274
  neorv32_uart_printf("\n#%u: FMIN.S (select minimum)...\n", test_cnt);
275
  err_cnt = 0;
276
  for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) {
277
    opa.binary_value = get_test_vector();
278
    opb.binary_value = get_test_vector();
279
    res_hw.float_value = riscv_intrinsic_fmins(opa.float_value, opb.float_value);
280
    res_sw.float_value = riscv_emulate_fmins(opa.float_value, opb.float_value);
281
    err_cnt += verify_result(i, opa.binary_value, opb.binary_value, res_sw.binary_value, res_hw.binary_value);
282
  }
283
  print_report(err_cnt);
284
  err_cnt_total += err_cnt;
285
  test_cnt++;
286
 
287
  neorv32_uart_printf("\n#%u: FMAX.S (select maximum)...\n", test_cnt);
288
  err_cnt = 0;
289
  for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) {
290
    opa.binary_value = get_test_vector();
291
    opb.binary_value = get_test_vector();
292
    res_hw.float_value = riscv_intrinsic_fmaxs(opa.float_value, opb.float_value);
293
    res_sw.float_value = riscv_emulate_fmaxs(opa.float_value, opb.float_value);
294
    err_cnt += verify_result(i, opa.binary_value, opb.binary_value, res_sw.binary_value, res_hw.binary_value);
295
  }
296
  print_report(err_cnt);
297
  err_cnt_total += err_cnt;
298
  test_cnt++;
299
#endif
300
 
301
 
302
// ----------------------------------------------------------------------------
303
// Comparison Tests
304
// ----------------------------------------------------------------------------
305
 
306
#if (RUN_COMPARE_TESTS != 0)
307
  neorv32_uart_printf("\n#%u: FEQ.S (compare if equal)...\n", test_cnt);
308
  err_cnt = 0;
309
  for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) {
310
    opa.binary_value = get_test_vector();
311
    opb.binary_value = get_test_vector();
312
    res_hw.binary_value = riscv_intrinsic_feqs(opa.float_value, opb.float_value);
313
    res_sw.binary_value = riscv_emulate_feqs(opa.float_value, opb.float_value);
314
    err_cnt += verify_result(i, opa.binary_value, opb.binary_value, res_sw.binary_value, res_hw.binary_value);
315
  }
316
  print_report(err_cnt);
317
  err_cnt_total += err_cnt;
318
  test_cnt++;
319
 
320
  neorv32_uart_printf("\n#%u: FLT.S (compare if less-than)...\n", test_cnt);
321
  err_cnt = 0;
322
  for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) {
323
    opa.binary_value = get_test_vector();
324
    opb.binary_value = get_test_vector();
325
    res_hw.binary_value = riscv_intrinsic_flts(opa.float_value, opb.float_value);
326
    res_sw.binary_value = riscv_emulate_flts(opa.float_value, opb.float_value);
327
    err_cnt += verify_result(i, opa.binary_value, opb.binary_value, res_sw.binary_value, res_hw.binary_value);
328
  }
329
  print_report(err_cnt);
330
  err_cnt_total += err_cnt;
331
  test_cnt++;
332
 
333
  neorv32_uart_printf("\n#%u: FLE.S (compare if less-than-or-equal)...\n", test_cnt);
334
  err_cnt = 0;
335
  for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) {
336
    opa.binary_value = get_test_vector();
337
    opb.binary_value = get_test_vector();
338
    res_hw.binary_value = riscv_intrinsic_fles(opa.float_value, opb.float_value);
339
    res_sw.binary_value = riscv_emulate_fles(opa.float_value, opb.float_value);
340
    err_cnt += verify_result(i, opa.binary_value, opb.binary_value, res_sw.binary_value, res_hw.binary_value);
341
  }
342
  print_report(err_cnt);
343
  err_cnt_total += err_cnt;
344
  test_cnt++;
345
#endif
346
 
347
 
348
// ----------------------------------------------------------------------------
349
// Sign-Injection Tests
350
// ----------------------------------------------------------------------------
351
 
352
#if (RUN_SGNINJ_TESTS != 0)
353
  neorv32_uart_printf("\n#%u: FSGNJ.S (sign-injection)...\n", test_cnt);
354
  err_cnt = 0;
355
  for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) {
356
    opa.binary_value = get_test_vector();
357
    opb.binary_value = get_test_vector();
358
    res_hw.float_value = riscv_intrinsic_fsgnjs(opa.float_value, opb.float_value);
359
    res_sw.float_value = riscv_emulate_fsgnjs(opa.float_value, opb.float_value);
360
    err_cnt += verify_result(i, opa.binary_value, opb.binary_value, res_sw.binary_value, res_hw.binary_value);
361
  }
362
  print_report(err_cnt);
363
  err_cnt_total += err_cnt;
364
  test_cnt++;
365
 
366
  neorv32_uart_printf("\n#%u: FSGNJN.S (sign-injection NOT)...\n", test_cnt);
367
  err_cnt = 0;
368
  for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) {
369
    opa.binary_value = get_test_vector();
370
    opb.binary_value = get_test_vector();
371
    res_hw.float_value = riscv_intrinsic_fsgnjns(opa.float_value, opb.float_value);
372
    res_sw.float_value = riscv_emulate_fsgnjns(opa.float_value, opb.float_value);
373
    err_cnt += verify_result(i, opa.binary_value, opb.binary_value, res_sw.binary_value, res_hw.binary_value);
374
  }
375
  print_report(err_cnt);
376
  err_cnt_total += err_cnt;
377
  test_cnt++;
378
 
379
  neorv32_uart_printf("\n#%u: FSGNJX.S (sign-injection XOR)...\n", test_cnt);
380
  err_cnt = 0;
381
  for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) {
382
    opa.binary_value = get_test_vector();
383
    opb.binary_value = get_test_vector();
384
    res_hw.float_value = riscv_intrinsic_fsgnjxs(opa.float_value, opb.float_value);
385
    res_sw.float_value = riscv_emulate_fsgnjxs(opa.float_value, opb.float_value);
386
    err_cnt += verify_result(i, opa.binary_value, opb.binary_value, res_sw.binary_value, res_hw.binary_value);
387
  }
388
  print_report(err_cnt);
389
  err_cnt_total += err_cnt;
390
  test_cnt++;
391
#endif
392
 
393
 
394
// ----------------------------------------------------------------------------
395
// Classify Tests
396
// ----------------------------------------------------------------------------
397
 
398
#if (RUN_CLASSIFY_TESTS != 0)
399
  neorv32_uart_printf("\n#%u: FCLASS.S (classify)...\n", test_cnt);
400
  err_cnt = 0;
401
  for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) {
402
    opa.binary_value = get_test_vector();
403
    res_hw.binary_value = riscv_intrinsic_fclasss(opa.float_value);
404
    res_sw.binary_value = riscv_emulate_fclasss(opa.float_value);
405
    err_cnt += verify_result(i, opa.binary_value, 0, res_sw.binary_value, res_hw.binary_value);
406
  }
407
  print_report(err_cnt);
408
  err_cnt_total += err_cnt;
409
  test_cnt++;
410
#endif
411
 
412
 
413
// ----------------------------------------------------------------------------
414
// UNSUPPORTED Instructions Tests - Execution should raise illegal instruction exception
415
// ----------------------------------------------------------------------------
416
 
417
#if (RUN_UNAVAIL_TESTS != 0)
418
  neorv32_uart_printf("\n# unsupported FDIV.S (division) [illegal instruction]...\n");
419
  neorv32_cpu_csr_write(CSR_MCAUSE, 0);
420
  opa.binary_value = get_test_vector();
421
  opb.binary_value = get_test_vector();
422
  riscv_intrinsic_fdivs(opa.float_value, opb.float_value);
423 56 zero_gravi
  if (neorv32_cpu_csr_read(CSR_MCAUSE) != TRAP_CODE_I_ILLEGAL) {
424 55 zero_gravi
    neorv32_uart_printf("%c[1m[FAILED]%c[0m\n", 27, 27);
425
    err_cnt_total++;
426
  }
427
  else {
428
    neorv32_uart_printf("%c[1m[ok]%c[0m\n", 27, 27);
429
  }
430
 
431
  neorv32_uart_printf("\n# unsupported FSQRT.S (square root) [illegal instruction]...\n");
432
  neorv32_cpu_csr_write(CSR_MCAUSE, 0);
433
  opa.binary_value = get_test_vector();
434
  opb.binary_value = get_test_vector();
435
  riscv_intrinsic_fsqrts(opa.float_value);
436 56 zero_gravi
  if (neorv32_cpu_csr_read(CSR_MCAUSE) != TRAP_CODE_I_ILLEGAL) {
437 55 zero_gravi
    neorv32_uart_printf("%c[1m[FAILED]%c[0m\n", 27, 27);
438
    err_cnt_total++;
439
  }
440
  else {
441
    neorv32_uart_printf("%c[1m[ok]%c[0m\n", 27, 27);
442
  }
443
 
444
  neorv32_uart_printf("\n# unsupported FMADD.S (fused multiply-add) [illegal instruction]...\n");
445
  neorv32_cpu_csr_write(CSR_MCAUSE, 0);
446
  opa.binary_value = get_test_vector();
447
  opb.binary_value = get_test_vector();
448
  riscv_intrinsic_fmadds(opa.float_value, opb.float_value, -opa.float_value);
449 56 zero_gravi
  if (neorv32_cpu_csr_read(CSR_MCAUSE) != TRAP_CODE_I_ILLEGAL) {
450 55 zero_gravi
    neorv32_uart_printf("%c[1m[FAILED]%c[0m\n", 27, 27);
451
    err_cnt_total++;
452
  }
453
  else {
454
    neorv32_uart_printf("%c[1m[ok]%c[0m\n", 27, 27);
455
  }
456
 
457
  neorv32_uart_printf("\n# unsupported FMSUB.S (fused multiply-sub) [illegal instruction]...\n");
458
  neorv32_cpu_csr_write(CSR_MCAUSE, 0);
459
  opa.binary_value = get_test_vector();
460
  opb.binary_value = get_test_vector();
461
  riscv_intrinsic_fmsubs(opa.float_value, opb.float_value, -opa.float_value);
462 56 zero_gravi
  if (neorv32_cpu_csr_read(CSR_MCAUSE) != TRAP_CODE_I_ILLEGAL) {
463 55 zero_gravi
    neorv32_uart_printf("%c[1m[FAILED]%c[0m\n", 27, 27);
464
    err_cnt_total++;
465
  }
466
  else {
467
    neorv32_uart_printf("%c[1m[ok]%c[0m\n", 27, 27);
468
  }
469
 
470
  neorv32_uart_printf("\n# unsupported FNMSUB.S (fused negated multiply-sub) [illegal instruction]...\n");
471
  neorv32_cpu_csr_write(CSR_MCAUSE, 0);
472
  opa.binary_value = get_test_vector();
473
  opb.binary_value = get_test_vector();
474
  riscv_intrinsic_fnmadds(opa.float_value, opb.float_value, -opa.float_value);
475 56 zero_gravi
  if (neorv32_cpu_csr_read(CSR_MCAUSE) != TRAP_CODE_I_ILLEGAL) {
476 55 zero_gravi
    neorv32_uart_printf("%c[1m[FAILED]%c[0m\n", 27, 27);
477
    err_cnt_total++;
478
  }
479
  else {
480
    neorv32_uart_printf("%c[1m[ok]%c[0m\n", 27, 27);
481
  }
482
 
483
  neorv32_uart_printf("\n# unsupported FNMADD.S (fused negated multiply-add) [illegal instruction]...\n");
484
  neorv32_cpu_csr_write(CSR_MCAUSE, 0);
485
  opa.binary_value = get_test_vector();
486
  opb.binary_value = get_test_vector();
487
  riscv_intrinsic_fnmadds(opa.float_value, opb.float_value, -opa.float_value);
488 56 zero_gravi
  if (neorv32_cpu_csr_read(CSR_MCAUSE) != TRAP_CODE_I_ILLEGAL) {
489 55 zero_gravi
    neorv32_uart_printf("%c[1m[FAILED]%c[0m\n", 27, 27);
490
    err_cnt_total++;
491
  }
492
  else {
493
    neorv32_uart_printf("%c[1m[ok]%c[0m\n", 27, 27);
494
  }
495
#endif
496
 
497
 
498 56 zero_gravi
// ----------------------------------------------------------------------------
499
// Instruction execution timing test
500
// ----------------------------------------------------------------------------
501
 
502
#if (RUN_TIMING_TESTS != 0)
503
 
504
  uint32_t time_start, time_sw, time_hw;
505
  const uint32_t num_runs = 4096;
506
 
507
  neorv32_uart_printf("\nAverage execution time tests (%u runs)\n", num_runs);
508
 
509
 
510
  // signed integer to float
511
  neorv32_uart_printf("FCVT.S.W: ");
512
  time_sw = 0;
513
  time_hw = 0;
514
  err_cnt = 0;
515
  for (i=0; i<num_runs; i++) {
516
    opa.binary_value = get_test_vector();
517
 
518
    // hardware execution time
519
    time_start = neorv32_cpu_csr_read(CSR_CYCLE);
520
    {
521
      res_hw.float_value = riscv_intrinsic_fcvt_sw((int32_t)opa.binary_value);
522
    }
523
    time_hw += neorv32_cpu_csr_read(CSR_CYCLE) - time_start;
524
    time_hw -= 4; // remove the 2 dummy instructions
525
 
526
    // software (emulation) execution time
527
    time_start = neorv32_cpu_csr_read(CSR_CYCLE);
528
    {
529
      res_sw.float_value = riscv_emulate_fcvt_sw((int32_t)opa.binary_value);
530
    }
531
    time_sw += neorv32_cpu_csr_read(CSR_CYCLE) - time_start;
532
 
533
    if (res_sw.binary_value != res_hw.binary_value) {
534
      err_cnt++;
535
    }
536
  }
537
 
538
  if (err_cnt == 0) {
539
    neorv32_uart_printf("cycles[SW] = %u vs. cycles[HW] = %u\n", time_sw/num_runs, time_hw/num_runs);
540
  }
541
  else {
542
    neorv32_uart_printf("%c[1m[TEST FAILED!]%c[0m\n", 27, 27);
543
    err_cnt_total++;
544
  }
545
 
546
 
547
  // float to signed integer
548
  neorv32_uart_printf("FCVT.W.S: ");
549
  time_sw = 0;
550
  time_hw = 0;
551
  err_cnt = 0;
552
  for (i=0; i<num_runs; i++) {
553
    opa.binary_value = get_test_vector();
554
 
555
    // hardware execution time
556
    time_start = neorv32_cpu_csr_read(CSR_CYCLE);
557
    {
558
      res_hw.binary_value = (uint32_t)riscv_intrinsic_fcvt_ws(opa.float_value);
559
    }
560
    time_hw += neorv32_cpu_csr_read(CSR_CYCLE) - time_start;
561
    time_hw -= 4; // remove the 2 dummy instructions
562
 
563
    // software (emulation) execution time
564
    time_start = neorv32_cpu_csr_read(CSR_CYCLE);
565
    {
566
      res_sw.binary_value = (uint32_t)riscv_emulate_fcvt_ws(opa.float_value);
567
    }
568
    time_sw += neorv32_cpu_csr_read(CSR_CYCLE) - time_start;
569
 
570
    if (res_sw.binary_value != res_hw.binary_value) {
571
      err_cnt++;
572
    }
573
  }
574
 
575
  if (err_cnt == 0) {
576
    neorv32_uart_printf("cycles[SW] = %u vs. cycles[HW] = %u\n", time_sw/num_runs, time_hw/num_runs);
577
  }
578
  else {
579
    neorv32_uart_printf("%c[1m[TEST FAILED!]%c[0m\n", 27, 27);
580
    err_cnt_total++;
581
  }
582
 
583
 
584
  // addition
585
  neorv32_uart_printf("FADD.S:   ");
586
  time_sw = 0;
587
  time_hw = 0;
588
  err_cnt = 0;
589
  for (i=0; i<num_runs; i++) {
590
    opa.binary_value = get_test_vector();
591
    opb.binary_value = get_test_vector();
592
 
593
    // hardware execution time
594
    time_start = neorv32_cpu_csr_read(CSR_CYCLE);
595
    {
596
      res_hw.float_value = riscv_intrinsic_fadds(opa.float_value, opb.float_value);
597
    }
598
    time_hw += neorv32_cpu_csr_read(CSR_CYCLE) - time_start;
599
    time_hw -= 4; // remove the 2 dummy instructions
600
 
601
    // software (emulation) execution time
602
    time_start = neorv32_cpu_csr_read(CSR_CYCLE);
603
    {
604
      res_sw.float_value = riscv_emulate_fadds(opa.float_value, opb.float_value);
605
    }
606
    time_sw += neorv32_cpu_csr_read(CSR_CYCLE) - time_start;
607
 
608
    if (res_sw.binary_value != res_hw.binary_value) {
609
      err_cnt++;
610
    }
611
  }
612
 
613
  if (err_cnt == 0) {
614
    neorv32_uart_printf("cycles[SW] = %u vs. cycles[HW] = %u\n", time_sw/num_runs, time_hw/num_runs);
615
  }
616
  else {
617
    neorv32_uart_printf("%c[1m[TEST FAILED!]%c[0m\n", 27, 27);
618
    err_cnt_total++;
619
  }
620
 
621
 
622
  // subtraction
623
  neorv32_uart_printf("FSUB.S:   ");
624
  time_sw = 0;
625
  time_hw = 0;
626
  err_cnt = 0;
627
  for (i=0; i<num_runs; i++) {
628
    opa.binary_value = get_test_vector();
629
    opb.binary_value = get_test_vector();
630
 
631
    // hardware execution time
632
    time_start = neorv32_cpu_csr_read(CSR_CYCLE);
633
    {
634
      res_hw.float_value = riscv_intrinsic_fsubs(opa.float_value, opb.float_value);
635
    }
636
    time_hw += neorv32_cpu_csr_read(CSR_CYCLE) - time_start;
637
    time_hw -= 4; // remove the 2 dummy instructions
638
 
639
    // software (emulation) execution time
640
    time_start = neorv32_cpu_csr_read(CSR_CYCLE);
641
    {
642
      res_sw.float_value = riscv_emulate_fsubs(opa.float_value, opb.float_value);
643
    }
644
    time_sw += neorv32_cpu_csr_read(CSR_CYCLE) - time_start;
645
 
646
    if (res_sw.binary_value != res_hw.binary_value) {
647
      err_cnt++;
648
    }
649
  }
650
 
651
  if (err_cnt == 0) {
652
    neorv32_uart_printf("cycles[SW] = %u vs. cycles[HW] = %u\n", time_sw/num_runs, time_hw/num_runs);
653
  }
654
  else {
655
    neorv32_uart_printf("%c[1m[TEST FAILED!]%c[0m\n", 27, 27);
656
    err_cnt_total++;
657
  }
658
 
659
 
660
  // multiplication
661
  neorv32_uart_printf("FMUL.S:   ");
662
  time_sw = 0;
663
  time_hw = 0;
664
  err_cnt = 0;
665
  for (i=0; i<num_runs; i++) {
666
    opa.binary_value = get_test_vector();
667
    opb.binary_value = get_test_vector();
668
 
669
    // hardware execution time
670
    time_start = neorv32_cpu_csr_read(CSR_CYCLE);
671
    {
672
      res_hw.float_value = riscv_intrinsic_fmuls(opa.float_value, opb.float_value);
673
    }
674
    time_hw += neorv32_cpu_csr_read(CSR_CYCLE) - time_start;
675
    time_hw -= 4; // remove the 2 dummy instructions
676
 
677
    // software (emulation) execution time
678
    time_start = neorv32_cpu_csr_read(CSR_CYCLE);
679
    {
680
      res_sw.float_value = riscv_emulate_fmuls(opa.float_value, opb.float_value);
681
    }
682
    time_sw += neorv32_cpu_csr_read(CSR_CYCLE) - time_start;
683
 
684
    if (res_sw.binary_value != res_hw.binary_value) {
685
      err_cnt++;
686
    }
687
  }
688
 
689
  if (err_cnt == 0) {
690
    neorv32_uart_printf("cycles[SW] = %u vs. cycles[HW] = %u\n", time_sw/num_runs, time_hw/num_runs);
691
  }
692
  else {
693
    neorv32_uart_printf("%c[1m[TEST FAILED!]%c[0m\n", 27, 27);
694
    err_cnt_total++;
695
  }
696
 
697
 
698
  // Max
699
  neorv32_uart_printf("FMAX.S:   ");
700
  time_sw = 0;
701
  time_hw = 0;
702
  err_cnt = 0;
703
  for (i=0; i<num_runs; i++) {
704
    opa.binary_value = get_test_vector();
705
    opb.binary_value = get_test_vector();
706
 
707
    // hardware execution time
708
    time_start = neorv32_cpu_csr_read(CSR_CYCLE);
709
    {
710
      res_hw.float_value = riscv_intrinsic_fmaxs(opa.float_value, opb.float_value);
711
    }
712
    time_hw += neorv32_cpu_csr_read(CSR_CYCLE) - time_start;
713
    time_hw -= 4; // remove the 2 dummy instructions
714
 
715
    // software (emulation) execution time
716
    time_start = neorv32_cpu_csr_read(CSR_CYCLE);
717
    {
718
      res_sw.float_value = riscv_emulate_fmaxs(opa.float_value, opb.float_value);
719
    }
720
    time_sw += neorv32_cpu_csr_read(CSR_CYCLE) - time_start;
721
 
722
    if (res_sw.binary_value != res_hw.binary_value) {
723
      err_cnt++;
724
    }
725
  }
726
 
727
  if (err_cnt == 0) {
728
    neorv32_uart_printf("cycles[SW] = %u vs. cycles[HW] = %u\n", time_sw/num_runs, time_hw/num_runs);
729
  }
730
  else {
731
    neorv32_uart_printf("%c[1m[TEST FAILED!]%c[0m\n", 27, 27);
732
    err_cnt_total++;
733
  }
734
 
735
 
736
  // Comparison
737
  neorv32_uart_printf("FLE.S:    ");
738
  time_sw = 0;
739
  time_hw = 0;
740
  err_cnt = 0;
741
  for (i=0; i<num_runs; i++) {
742
    opa.binary_value = get_test_vector();
743
    opb.binary_value = get_test_vector();
744
 
745
    // hardware execution time
746
    time_start = neorv32_cpu_csr_read(CSR_CYCLE);
747
    {
748
      res_hw.float_value = riscv_intrinsic_fles(opa.float_value, opb.float_value);
749
    }
750
    time_hw += neorv32_cpu_csr_read(CSR_CYCLE) - time_start;
751
    time_hw -= 4; // remove the 2 dummy instructions
752
 
753
    // software (emulation) execution time
754
    time_start = neorv32_cpu_csr_read(CSR_CYCLE);
755
    {
756
      res_sw.float_value = riscv_emulate_fles(opa.float_value, opb.float_value);
757
    }
758
    time_sw += neorv32_cpu_csr_read(CSR_CYCLE) - time_start;
759
 
760
    if (res_sw.binary_value != res_hw.binary_value) {
761
      err_cnt++;
762
    }
763
  }
764
 
765
  if (err_cnt == 0) {
766
    neorv32_uart_printf("cycles[SW] = %u vs. cycles[HW] = %u\n", time_sw/num_runs, time_hw/num_runs);
767
  }
768
  else {
769
    neorv32_uart_printf("%c[1m[TEST FAILED!]%c[0m\n", 27, 27);
770
    err_cnt_total++;
771
  }
772
 
773
 
774
  // Sign-injection
775
  neorv32_uart_printf("FSGNJX.S: ");
776
  time_sw = 0;
777
  time_hw = 0;
778
  err_cnt = 0;
779
  for (i=0; i<num_runs; i++) {
780
    opa.binary_value = get_test_vector();
781
    opb.binary_value = get_test_vector();
782
 
783
    // hardware execution time
784
    time_start = neorv32_cpu_csr_read(CSR_CYCLE);
785
    {
786
      res_hw.float_value = riscv_intrinsic_fsgnjxs(opa.float_value, opb.float_value);
787
    }
788
    time_hw += neorv32_cpu_csr_read(CSR_CYCLE) - time_start;
789
    time_hw -= 4; // remove the 2 dummy instructions
790
 
791
    // software (emulation) execution time
792
    time_start = neorv32_cpu_csr_read(CSR_CYCLE);
793
    {
794
      res_sw.float_value = riscv_emulate_fsgnjxs(opa.float_value, opb.float_value);
795
    }
796
    time_sw += neorv32_cpu_csr_read(CSR_CYCLE) - time_start;
797
 
798
    if (res_sw.binary_value != res_hw.binary_value) {
799
      err_cnt++;
800
    }
801
  }
802
 
803
  if (err_cnt == 0) {
804
    neorv32_uart_printf("cycles[SW] = %u vs. cycles[HW] = %u\n", time_sw/num_runs, time_hw/num_runs);
805
  }
806
  else {
807
    neorv32_uart_printf("%c[1m[TEST FAILED!]%c[0m\n", 27, 27);
808
    err_cnt_total++;
809
  }
810
#endif
811
 
812
 
813
// ----------------------------------------------------------------------------
814
// Final report
815
// ----------------------------------------------------------------------------
816
 
817 55 zero_gravi
  if (err_cnt_total != 0) {
818
    neorv32_uart_printf("\n%c[1m[ZFINX EXTENSION VERIFICATION FAILED!]%c[0m\n", 27, 27);
819
    neorv32_uart_printf("%u errors in %u test cases\n", err_cnt_total, test_cnt*(uint32_t)NUM_TEST_CASES);
820 60 zero_gravi
    return 1;
821 55 zero_gravi
  }
822
  else {
823
    neorv32_uart_printf("\n%c[1m[Zfinx extension verification successful!]%c[0m\n", 27, 27);
824 60 zero_gravi
    return 0;
825 55 zero_gravi
  }
826
 
827
}
828
 
829
 
830
/**********************************************************************//**
831
 * Generate 32-bit test data (including special values like INFINITY every now and then).
832
 *
833
 * @return Test data (32-bit).
834
 **************************************************************************/
835
uint32_t get_test_vector(void) {
836
 
837
  float_conv_t tmp;
838
 
839
  // generate special value "every" ~256th time this function is called
840
  if ((xorshift32() & 0xff) == 0xff) {
841
 
842
    switch((xorshift32() >> 10) & 0x3) { // random decision which special value we are taking
843
      case  0: tmp.float_value  = +INFINITY; break;
844
      case  1: tmp.float_value  = -INFINITY; break;
845
      case  2: tmp.float_value  = +0.0f; break;
846
      case  3: tmp.float_value  = -0.0f; break;
847
      case  4: tmp.binary_value = 0x7fffffff; break;
848
      case  5: tmp.binary_value = 0xffffffff; break;
849
      case  6: tmp.float_value  = NAN; break;
850
      case  7: tmp.float_value  = NAN; break; // FIXME signaling_NAN?
851
      default: tmp.float_value  = NAN; break;
852
    }
853
  }
854
  else {
855
    tmp.binary_value = xorshift32();
856
  }
857
 
858
  return tmp.binary_value;
859
}
860
 
861
 
862
/**********************************************************************//**
863
 * PSEUDO-RANDOM number generator.
864
 *
865
 * @return Random data (32-bit).
866
 **************************************************************************/
867
uint32_t xorshift32(void) {
868
 
869
  static uint32_t x32 = 314159265;
870
 
871
  x32 ^= x32 << 13;
872
  x32 ^= x32 >> 17;
873
  x32 ^= x32 << 5;
874
 
875
  return x32;
876
}
877
 
878
 
879
/**********************************************************************//**
880
 * Verify results (software reference vs. actual hardware).
881
 *
882
 * @param[in] num Test case number
883
 * @param[in] opa Operand 1
884
 * @param[in] opb Operand 2
885
 * @param[in] ref Software reference
886
 * @param[in] res Actual results from hardware
887
 * @return zero if results are equal.
888
 **************************************************************************/
889
uint32_t verify_result(uint32_t num, uint32_t opa, uint32_t opb, uint32_t ref, uint32_t res) {
890
 
891
#if (SILENT_MODE == 0)
892
  neorv32_uart_printf("%u: opa = 0x%x, opb = 0x%x : ref[SW] = 0x%x vs. res[HW] = 0x%x ", num, opa, opb, ref, res);
893
#endif
894
 
895
  if (ref != res) {
896
#if (SILENT_MODE != 0)
897
    neorv32_uart_printf("%u: opa = 0x%x, opb = 0x%x : ref[SW] = 0x%x vs. res[HW] = 0x%x ", num, opa, opb, ref, res);
898
#endif
899
    neorv32_uart_printf("%c[1m[FAILED]%c[0m\n", 27, 27);
900
    return 1;
901
  }
902
  else {
903
#if (SILENT_MODE == 0)
904
    neorv32_uart_printf("%c[1m[ok]%c[0m\n", 27, 27);
905
#endif
906
    return 0;
907
  }
908
}
909
 
910
 
911
/**********************************************************************//**
912
 * Print test report.
913
 *
914
 * @param[in] num_err Number or errors in this test.
915
 **************************************************************************/
916
void print_report(uint32_t num_err) {
917
 
918
  neorv32_uart_printf("Errors: %u/%u ", num_err, (uint32_t)NUM_TEST_CASES);
919
 
920
  if (num_err == 0) {
921
    neorv32_uart_printf("%c[1m[ok]%c[0m\n", 27, 27);
922
  }
923
  else {
924
    neorv32_uart_printf("%c[1m[FAILED]%c[0m\n", 27, 27);
925
  }
926
}

powered by: WebSVN 2.1.0

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