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 65

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

powered by: WebSVN 2.1.0

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