URL
https://opencores.org/ocsvn/neorv32/neorv32/trunk
Subversion Repositories neorv32
Compare Revisions
- This comparison shows the changes necessary to convert path
/neorv32/trunk/sw/example
- from Rev 54 to Rev 55
- ↔ Reverse comparison
Rev 54 → Rev 55
/bit_manipulation/makefile
1,11 → 1,11
################################################################################################# |
# << NEORV32 - Application Makefile >> # |
# ********************************************************************************************* # |
# Make sure to add the riscv GCC compiler's bin folder to your PATH environment variable. # |
# Make sure to add the RISC-V GCC compiler's bin folder to your PATH environment variable. # |
# ********************************************************************************************* # |
# BSD 3-Clause License # |
# # |
# Copyright (c) 2020, Stephan Nolting. All rights reserved. # |
# Copyright (c) 2021, Stephan Nolting. All rights reserved. # |
# # |
# Redistribution and use in source and binary forms, with or without modification, are # |
# permitted provided that the following conditions are met: # |
126,7 → 126,7
IMAGE_GEN = $(NEORV32_EXG_PATH)/image_gen |
|
# Compiler & linker flags |
CC_OPTS = $(MARCH) $(MABI) $(EFFORT) -Wall -ffunction-sections -fdata-sections -nostartfiles |
CC_OPTS = $(MARCH) $(MABI) $(EFFORT) -Wall -ffunction-sections -fdata-sections -nostartfiles -mno-fdiv |
CC_OPTS += -Wl,--gc-sections -lm -lc -lgcc -lc |
# This accelerates instruction fetch after branches when C extension is enabled (irrelevant when C extension is disabled) |
CC_OPTS += -falign-functions=4 -falign-labels=4 -falign-loops=4 -falign-jumps=4 |
/bit_manipulation/neorv32_b_extension_intrinsics.h
1,6 → 1,9
// ################################################################################################# |
// # << NEORV32 - Intrinsics + Emulation Functions for the B.Zbb CPU extensions >> # |
// # << NEORV32 - Intrinsics + Emulation Functions for the B CPU extensions >> # |
// # ********************************************************************************************* # |
// # The intrinsics provided by this library allow to use the hardware bit manipulation unit of # |
// # the RISC-V B CPU extension without the need for B support by the compiler. # |
// # ********************************************************************************************* # |
// # BSD 3-Clause License # |
// # # |
// # Copyright (c) 2021, Stephan Nolting. All rights reserved. # |
36,9 → 39,9
/**********************************************************************//** |
* @file bit_manipulation/neorv32_b_extension_intrinsics.h |
* @author Stephan Nolting |
* @brief "Intrinsic" library for the NEORV32 bit manipulation (B.Zbb) extension. Also provides emulation functions for all intrinsics (functionality re-built in pure software). |
* @brief "Intrinsic" library for the NEORV32 bit manipulation B extension. Also provides emulation functions for all intrinsics (functionality re-built in pure software). |
* |
* @warning This library is just a temporary fall-back until the B/Zbb extensions are supported by the upstream RISC-V GCC port. |
* @warning This library is just a temporary fall-back until the B extensions are supported by the upstream RISC-V GCC port. |
**************************************************************************/ |
|
#ifndef neorv32_b_extension_intrinsics_h |
65,7 → 68,11
uint32_t __attribute__ ((noinline)) riscv_intrinsic_clz(uint32_t rs1) { |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = rs1; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], x0" : : [input_i] "r" (tmp_a)); |
|
// clz a0, a0 |
CUSTOM_INSTR_R1_TYPE(0b0110000, 0b00000, a0, 0b001, a0, 0b0010011); |
|
84,7 → 91,11
uint32_t __attribute__ ((noinline)) riscv_intrinsic_ctz(uint32_t rs1) { |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = rs1; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], x0" : : [input_i] "r" (tmp_a)); |
|
// ctz a0, a0 |
CUSTOM_INSTR_R1_TYPE(0b0110000, 0b00001, a0, 0b001, a0, 0b0010011); |
|
103,7 → 114,11
uint32_t __attribute__ ((noinline)) riscv_intrinsic_cpop(uint32_t rs1) { |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = rs1; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], x0" : : [input_i] "r" (tmp_a)); |
|
// cpop a0, a0 |
CUSTOM_INSTR_R1_TYPE(0b0110000, 0b00010, a0, 0b001, a0, 0b0010011); |
|
122,7 → 137,11
uint32_t __attribute__ ((noinline)) riscv_intrinsic_sextb(uint32_t rs1) { |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = rs1; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], x0" : : [input_i] "r" (tmp_a)); |
|
// sext.b a0, a0 |
CUSTOM_INSTR_R1_TYPE(0b0110000, 0b00100, a0, 0b001, a0, 0b0010011); |
|
141,7 → 160,11
uint32_t __attribute__ ((noinline)) riscv_intrinsic_sexth(uint32_t rs1) { |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = rs1; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], x0" : : [input_i] "r" (tmp_a)); |
|
// sext.h a0, a0 |
CUSTOM_INSTR_R1_TYPE(0b0110000, 0b00101, a0, 0b001, a0, 0b0010011); |
|
161,9 → 184,14
uint32_t __attribute__ ((noinline)) riscv_intrinsic_min(uint32_t rs1, uint32_t rs2) { |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = rs1; |
register uint32_t tmp_b __asm__ ("a1") = rs2; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); |
|
// min a0, a0, a1 |
CUSTOM_INSTR_R_TYPE(0b0000101, a1, a0, 0b100, a0, 0b0110011); |
CUSTOM_INSTR_R2_TYPE(0b0000101, a1, a0, 0b100, a0, 0b0110011); |
|
return result; |
} |
181,9 → 209,14
uint32_t __attribute__ ((noinline)) riscv_intrinsic_minu(uint32_t rs1, uint32_t rs2) { |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = rs1; |
register uint32_t tmp_b __asm__ ("a1") = rs2; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); |
|
// minu a0, a0, a1 |
CUSTOM_INSTR_R_TYPE(0b0000101, a1, a0, 0b101, a0, 0b0110011); |
CUSTOM_INSTR_R2_TYPE(0b0000101, a1, a0, 0b101, a0, 0b0110011); |
|
return result; |
} |
201,9 → 234,14
uint32_t __attribute__ ((noinline)) riscv_intrinsic_max(uint32_t rs1, uint32_t rs2) { |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = rs1; |
register uint32_t tmp_b __asm__ ("a1") = rs2; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); |
|
// max a0, a0, a1 |
CUSTOM_INSTR_R_TYPE(0b0000101, a1, a0, 0b110, a0, 0b0110011); |
CUSTOM_INSTR_R2_TYPE(0b0000101, a1, a0, 0b110, a0, 0b0110011); |
|
return result; |
} |
221,9 → 259,14
uint32_t __attribute__ ((noinline)) riscv_intrinsic_maxu(uint32_t rs1, uint32_t rs2) { |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = rs1; |
register uint32_t tmp_b __asm__ ("a1") = rs2; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); |
|
// maxu a0, a0, a1 |
CUSTOM_INSTR_R_TYPE(0b0000101, a1, a0, 0b111, a0, 0b0110011); |
CUSTOM_INSTR_R2_TYPE(0b0000101, a1, a0, 0b111, a0, 0b0110011); |
|
return result; |
} |
241,9 → 284,14
uint32_t __attribute__ ((noinline)) riscv_intrinsic_pack(uint32_t rs1, uint32_t rs2) { |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = rs1; |
register uint32_t tmp_b __asm__ ("a1") = rs2; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); |
|
// maxu a0, a0, a1 |
CUSTOM_INSTR_R_TYPE(0b0000100, a1, a0, 0b100, a0, 0b0110011); |
CUSTOM_INSTR_R2_TYPE(0b0000100, a1, a0, 0b100, a0, 0b0110011); |
|
return result; |
} |
261,9 → 309,14
uint32_t __attribute__ ((noinline)) riscv_intrinsic_andn(uint32_t rs1, uint32_t rs2) { |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = rs1; |
register uint32_t tmp_b __asm__ ("a1") = rs2; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); |
|
// andn a0, a0, a1 |
CUSTOM_INSTR_R_TYPE(0b0100000, a1, a0, 0b111, a0, 0b0110011); |
CUSTOM_INSTR_R2_TYPE(0b0100000, a1, a0, 0b111, a0, 0b0110011); |
|
return result; |
} |
281,9 → 334,14
uint32_t __attribute__ ((noinline)) riscv_intrinsic_orn(uint32_t rs1, uint32_t rs2) { |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = rs1; |
register uint32_t tmp_b __asm__ ("a1") = rs2; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); |
|
// orn a0, a0, a1 |
CUSTOM_INSTR_R_TYPE(0b0100000, a1, a0, 0b110, a0, 0b0110011); |
CUSTOM_INSTR_R2_TYPE(0b0100000, a1, a0, 0b110, a0, 0b0110011); |
|
return result; |
} |
301,9 → 359,14
uint32_t __attribute__ ((noinline)) riscv_intrinsic_xnor(uint32_t rs1, uint32_t rs2) { |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = rs1; |
register uint32_t tmp_b __asm__ ("a1") = rs2; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); |
|
// xnor a0, a0, a1 |
CUSTOM_INSTR_R_TYPE(0b0100000, a1, a0, 0b100, a0, 0b0110011); |
CUSTOM_INSTR_R2_TYPE(0b0100000, a1, a0, 0b100, a0, 0b0110011); |
|
return result; |
} |
321,9 → 384,14
uint32_t __attribute__ ((noinline)) riscv_intrinsic_rol(uint32_t rs1, uint32_t rs2) { |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = rs1; |
register uint32_t tmp_b __asm__ ("a1") = rs2; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); |
|
// rol a0, a0, a1 |
CUSTOM_INSTR_R_TYPE(0b0110000, a1, a0, 0b001, a0, 0b0110011); |
CUSTOM_INSTR_R2_TYPE(0b0110000, a1, a0, 0b001, a0, 0b0110011); |
|
return result; |
} |
341,9 → 409,14
uint32_t __attribute__ ((noinline)) riscv_intrinsic_ror(uint32_t rs1, uint32_t rs2) { |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = rs1; |
register uint32_t tmp_b __asm__ ("a1") = rs2; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); |
|
// ror a0, a0, a1 |
CUSTOM_INSTR_R_TYPE(0b0110000, a1, a0, 0b101, a0, 0b0110011); |
CUSTOM_INSTR_R2_TYPE(0b0110000, a1, a0, 0b101, a0, 0b0110011); |
|
return result; |
} |
361,7 → 434,11
uint32_t __attribute__ ((noinline)) riscv_intrinsic_rori20(uint32_t rs1) { |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = rs1; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], x0" : : [input_i] "r" (tmp_a)); |
|
// rori a0, a0, 20 |
CUSTOM_INSTR_R1_TYPE(0b0110000, 0b10100, a0, 0b101, a0, 0b0010011); |
|
380,7 → 457,11
uint32_t __attribute__ ((noinline)) riscv_intrinsic_orcb(uint32_t rs1) { |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = rs1; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], x0" : : [input_i] "r" (tmp_a)); |
|
// gorci a0, a0, 7 (pseudo-instruction: orc.b a0, a0) |
CUSTOM_INSTR_R1_TYPE(0b0010100, 0b00111, a0, 0b101, a0, 0b0010011); |
|
399,7 → 480,11
uint32_t __attribute__ ((noinline)) riscv_intrinsic_rev8(uint32_t rs1) { |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = rs1; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], x0" : : [input_i] "r" (tmp_a)); |
|
// grevi a0, a0, -8 (pseudo-instruction: rev8 a0, a0) |
CUSTOM_INSTR_R1_TYPE(0b0110100, 0b11000, a0, 0b101, a0, 0b0010011); |
|
424,9 → 509,15
uint32_t __attribute__ ((noinline)) riscv_intrinsic_sbclr(uint32_t rs1, uint32_t rs2) { |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = rs1; |
register uint32_t tmp_b __asm__ ("a1") = rs2; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); |
|
|
// sbclr a0, a0, a1 |
CUSTOM_INSTR_R_TYPE(0b0100100, a1, a0, 0b001, a0, 0b0110011); |
CUSTOM_INSTR_R2_TYPE(0b0100100, a1, a0, 0b001, a0, 0b0110011); |
|
return result; |
} |
444,9 → 535,15
uint32_t __attribute__ ((noinline)) riscv_intrinsic_sbset(uint32_t rs1, uint32_t rs2) { |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = rs1; |
register uint32_t tmp_b __asm__ ("a1") = rs2; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); |
|
|
// sbset a0, a0, a1 |
CUSTOM_INSTR_R_TYPE(0b0010100, a1, a0, 0b001, a0, 0b0110011); |
CUSTOM_INSTR_R2_TYPE(0b0010100, a1, a0, 0b001, a0, 0b0110011); |
|
return result; |
} |
464,9 → 561,15
uint32_t __attribute__ ((noinline)) riscv_intrinsic_sbinv(uint32_t rs1, uint32_t rs2) { |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = rs1; |
register uint32_t tmp_b __asm__ ("a1") = rs2; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); |
|
|
// sbinv a0, a0, a1 |
CUSTOM_INSTR_R_TYPE(0b0110100, a1, a0, 0b001, a0, 0b0110011); |
CUSTOM_INSTR_R2_TYPE(0b0110100, a1, a0, 0b001, a0, 0b0110011); |
|
return result; |
} |
484,9 → 587,15
uint32_t __attribute__ ((noinline)) riscv_intrinsic_sbext(uint32_t rs1, uint32_t rs2) { |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = rs1; |
register uint32_t tmp_b __asm__ ("a1") = rs2; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); |
|
|
// sbext a0, a0, a1 |
CUSTOM_INSTR_R_TYPE(0b0100100, a1, a0, 0b101, a0, 0b0110011); |
CUSTOM_INSTR_R2_TYPE(0b0100100, a1, a0, 0b101, a0, 0b0110011); |
|
return result; |
} |
504,7 → 613,11
uint32_t __attribute__ ((noinline)) riscv_intrinsic_sbclri20(uint32_t rs1) { |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = rs1; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], x0" : : [input_i] "r" (tmp_a)); |
|
// sbclri a0, a0, 20 |
CUSTOM_INSTR_R1_TYPE(0b0100100, 0b10100, a0, 0b001, a0, 0b0010011); |
|
524,7 → 637,11
uint32_t __attribute__ ((noinline)) riscv_intrinsic_sbseti20(uint32_t rs1) { |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = rs1; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], x0" : : [input_i] "r" (tmp_a)); |
|
// sbseti a0, a0, 20 |
CUSTOM_INSTR_R1_TYPE(0b0010100, 0b10100, a0, 0b001, a0, 0b0010011); |
|
544,7 → 661,11
uint32_t __attribute__ ((noinline)) riscv_intrinsic_sbinvi20(uint32_t rs1) { |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = rs1; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], x0" : : [input_i] "r" (tmp_a)); |
|
// sbinvi a0, a0, 20 |
CUSTOM_INSTR_R1_TYPE(0b0110100, 0b10100, a0, 0b001, a0, 0b0010011); |
|
564,7 → 685,11
uint32_t __attribute__ ((noinline)) riscv_intrinsic_sbexti20(uint32_t rs1) { |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = rs1; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], x0" : : [input_i] "r" (tmp_a)); |
|
// sbexti a0, a0, 20 |
CUSTOM_INSTR_R1_TYPE(0b0100100, 0b10100, a0, 0b101, a0, 0b0010011); |
|
573,7 → 698,7
|
|
// --------------------------------------------- |
// Zba - Single-bit instructions |
// Zba - Shifted-add instructions |
// --------------------------------------------- |
|
|
589,9 → 714,14
uint32_t __attribute__ ((noinline)) riscv_intrinsic_sh1add(uint32_t rs1, uint32_t rs2) { |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = rs1; |
register uint32_t tmp_b __asm__ ("a1") = rs2; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); |
|
// sh1add a0, a0, a1 |
CUSTOM_INSTR_R_TYPE(0b0010000, a1, a0, 0b010, a0, 0b0110011); |
CUSTOM_INSTR_R2_TYPE(0b0010000, a1, a0, 0b010, a0, 0b0110011); |
|
return result; |
} |
609,9 → 739,14
uint32_t __attribute__ ((noinline)) riscv_intrinsic_sh2add(uint32_t rs1, uint32_t rs2) { |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = rs1; |
register uint32_t tmp_b __asm__ ("a1") = rs2; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); |
|
// sh2add a0, a0, a1 |
CUSTOM_INSTR_R_TYPE(0b0010000, a1, a0, 0b100, a0, 0b0110011); |
CUSTOM_INSTR_R2_TYPE(0b0010000, a1, a0, 0b100, a0, 0b0110011); |
|
return result; |
} |
629,9 → 764,14
uint32_t __attribute__ ((noinline)) riscv_intrinsic_sh3add(uint32_t rs1, uint32_t rs2) { |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = rs1; |
register uint32_t tmp_b __asm__ ("a1") = rs2; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); |
|
// sh3add a0, a0, a1 |
CUSTOM_INSTR_R_TYPE(0b0010000, a1, a0, 0b110, a0, 0b0110011); |
CUSTOM_INSTR_R2_TYPE(0b0010000, a1, a0, 0b110, a0, 0b0110011); |
|
return result; |
} |
1036,7 → 1176,7
|
|
// --------------------------------------------- |
// Zba - Single-bit instructions |
// Zba - Shifted-add instructions |
// --------------------------------------------- |
|
|
/blink_led/makefile
1,11 → 1,11
################################################################################################# |
# << NEORV32 - Application Makefile >> # |
# ********************************************************************************************* # |
# Make sure to add the riscv GCC compiler's bin folder to your PATH environment variable. # |
# Make sure to add the RISC-V GCC compiler's bin folder to your PATH environment variable. # |
# ********************************************************************************************* # |
# BSD 3-Clause License # |
# # |
# Copyright (c) 2020, Stephan Nolting. All rights reserved. # |
# Copyright (c) 2021, Stephan Nolting. All rights reserved. # |
# # |
# Redistribution and use in source and binary forms, with or without modification, are # |
# permitted provided that the following conditions are met: # |
126,7 → 126,7
IMAGE_GEN = $(NEORV32_EXG_PATH)/image_gen |
|
# Compiler & linker flags |
CC_OPTS = $(MARCH) $(MABI) $(EFFORT) -Wall -ffunction-sections -fdata-sections -nostartfiles |
CC_OPTS = $(MARCH) $(MABI) $(EFFORT) -Wall -ffunction-sections -fdata-sections -nostartfiles -mno-fdiv |
CC_OPTS += -Wl,--gc-sections -lm -lc -lgcc -lc |
# This accelerates instruction fetch after branches when C extension is enabled (irrelevant when C extension is disabled) |
CC_OPTS += -falign-functions=4 -falign-labels=4 -falign-loops=4 -falign-jumps=4 |
/coremark/makefile
1,11 → 1,11
################################################################################################# |
# << NEORV32 - Application Makefile >> # |
# ********************************************************************************************* # |
# Make sure to add the riscv GCC compiler's bin folder to your PATH environment variable. # |
# Make sure to add the RISC-V GCC compiler's bin folder to your PATH environment variable. # |
# ********************************************************************************************* # |
# BSD 3-Clause License # |
# # |
# Copyright (c) 2020, Stephan Nolting. All rights reserved. # |
# Copyright (c) 2021, Stephan Nolting. All rights reserved. # |
# # |
# Redistribution and use in source and binary forms, with or without modification, are # |
# permitted provided that the following conditions are met: # |
126,7 → 126,7
IMAGE_GEN = $(NEORV32_EXG_PATH)/image_gen |
|
# Compiler & linker flags |
CC_OPTS = $(MARCH) $(MABI) $(EFFORT) -Wall -ffunction-sections -fdata-sections -nostartfiles |
CC_OPTS = $(MARCH) $(MABI) $(EFFORT) -Wall -ffunction-sections -fdata-sections -nostartfiles -mno-fdiv |
CC_OPTS += -Wl,--gc-sections -lm -lc -lgcc -lc |
# This accelerates instruction fetch after branches when C extension is enabled (irrelevant when C extension is disabled) |
CC_OPTS += -falign-functions=4 -falign-labels=4 -falign-loops=4 -falign-jumps=4 |
/cpu_test/main.c
206,7 → 206,7
// Test standard RISC-V performance counter [m]cycle[h] |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] [m]instret[h] counter test: ", cnt_test); |
neorv32_uart_printf("[%i] [m]instret[h] counter: ", cnt_test); |
|
cnt_test++; |
|
230,7 → 230,7
// Test standard RISC-V performance counter [m]instret[h] |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] [m]cycle[h] counter test: ", cnt_test); |
neorv32_uart_printf("[%i] [m]cycle[h] counter: ", cnt_test); |
|
cnt_test++; |
|
255,7 → 255,7
// Test mcountinhibt: inhibit auto-inc of [m]cycle |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] mcountinhibt.cy CSR test: ", cnt_test); |
neorv32_uart_printf("[%i] mcountinhibt.cy CSR: ", cnt_test); |
|
cnt_test++; |
|
291,7 → 291,7
// Test mcounteren: do not allow cycle[h] access from user-mode |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] mcounteren.cy CSR test: ", cnt_test); |
neorv32_uart_printf("[%i] mcounteren.cy CSR: ", cnt_test); |
|
cnt_test++; |
|
393,7 → 393,7
// External memory interface test |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] External memory access (@ 0x%x) test: ", cnt_test, (uint32_t)EXT_MEM_BASE); |
neorv32_uart_printf("[%i] External memory access (@ 0x%x): ", cnt_test, (uint32_t)EXT_MEM_BASE); |
|
if (is_simulation) { // check if this is a simulation |
if (SYSINFO_FEATURES & (1 << SYSINFO_FEATURES_MEM_EXT)) { |
441,7 → 441,7
//// Test FENCE.I instruction (instruction buffer / i-cache clear & reload) |
//// ---------------------------------------------------------- |
//neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
//neorv32_uart_printf("[%i] FENCE.I test: ", cnt_test); |
//neorv32_uart_printf("[%i] FENCE.I: ", cnt_test); |
// |
//// check if implemented |
//if (neorv32_cpu_csr_read(CSR_MZEXT) & (1 << CSR_MZEXT_ZIFENCEI)) { |
466,7 → 466,7
// Illegal CSR access (CSR not implemented) |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] Illegal CSR (0xfff) access test: ", cnt_test); |
neorv32_uart_printf("[%i] Illegal CSR (0xfff) access: ", cnt_test); |
|
cnt_test++; |
|
484,7 → 484,7
// Write-access to read-only CSR |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] Read-only CSR (time) write access test: ", cnt_test); |
neorv32_uart_printf("[%i] Read-only CSR (time) write access: ", cnt_test); |
|
cnt_test++; |
|
502,7 → 502,7
// No "real" CSR write access (because rs1 = r0) |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] Read-only CSR (time) no-write (rs1=0) access test: ", cnt_test); |
neorv32_uart_printf("[%i] Read-only CSR (time) no-write (rs1=0) access: ", cnt_test); |
|
cnt_test++; |
|
608,7 → 608,7
// Unaligned instruction address |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] I_ALIGN (instr. alignment) EXC test: ", cnt_test); |
neorv32_uart_printf("[%i] I_ALIGN (instr. alignment) EXC: ", cnt_test); |
|
// skip if C-mode is implemented |
if ((neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_C_EXT)) == 0) { |
636,7 → 636,7
// Instruction access fault |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] I_ACC (instr. bus access) EXC test: ", cnt_test); |
neorv32_uart_printf("[%i] I_ACC (instr. bus access) EXC: ", cnt_test); |
cnt_test++; |
|
// call unreachable aligned address |
654,7 → 654,7
// Illegal instruction |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] I_ILLEG (illegal instr.) EXC test: ", cnt_test); |
neorv32_uart_printf("[%i] I_ILLEG (illegal instr.) EXC: ", cnt_test); |
|
cnt_test++; |
|
680,7 → 680,7
// Illegal compressed instruction |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] CI_ILLEG (illegal compr. instr.) EXC test: ", cnt_test); |
neorv32_uart_printf("[%i] CI_ILLEG (illegal compr. instr.) EXC: ", cnt_test); |
|
// skip if C-mode is not implemented |
if ((neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_C_EXT)) != 0) { |
712,7 → 712,7
// Breakpoint instruction |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] BREAK (break instr.) EXC test: ", cnt_test); |
neorv32_uart_printf("[%i] BREAK (break instr.) EXC: ", cnt_test); |
cnt_test++; |
|
asm volatile("EBREAK"); |
729,7 → 729,7
// Unaligned load address |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] L_ALIGN (load addr alignment) EXC test: ", cnt_test); |
neorv32_uart_printf("[%i] L_ALIGN (load addr alignment) EXC: ", cnt_test); |
cnt_test++; |
|
// load from unaligned address |
747,7 → 747,7
// Load access fault |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] L_ACC (load bus access) EXC test: ", cnt_test); |
neorv32_uart_printf("[%i] L_ACC (load bus access) EXC: ", cnt_test); |
cnt_test++; |
|
// load from unreachable aligned address |
765,7 → 765,7
// Unaligned store address |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] S_ALIGN (store addr alignment) EXC test: ", cnt_test); |
neorv32_uart_printf("[%i] S_ALIGN (store addr alignment) EXC: ", cnt_test); |
cnt_test++; |
|
// store to unaligned address |
783,7 → 783,7
// Store access fault |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] S_ACC (store bus access) EXC test: ", cnt_test); |
neorv32_uart_printf("[%i] S_ACC (store bus access) EXC: ", cnt_test); |
cnt_test++; |
|
// store to unreachable aligned address |
801,7 → 801,7
// Environment call from M-mode |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] ENVCALL (ecall instr.) from M-mode EXC test: ", cnt_test); |
neorv32_uart_printf("[%i] ENVCALL (ecall instr.) from M-mode EXC: ", cnt_test); |
cnt_test++; |
|
asm volatile("ECALL"); |
818,7 → 818,7
// Environment call from U-mode |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] ENVCALL (ecall instr.) from U-mode EXC test: ", cnt_test); |
neorv32_uart_printf("[%i] ENVCALL (ecall instr.) from U-mode EXC: ", cnt_test); |
|
// skip if U-mode is not implemented |
if (neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_U_EXT)) { |
848,7 → 848,7
// Machine timer interrupt (MTIME) |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] MTI (machine timer) IRQ test: ", cnt_test); |
neorv32_uart_printf("[%i] MTI (machine timer) IRQ: ", cnt_test); |
|
if (neorv32_mtime_available()) { |
cnt_test++; |
879,7 → 879,7
// Machine software interrupt (MSI) via testbench |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] MSI (via testbench) IRQ test: ", cnt_test); |
neorv32_uart_printf("[%i] MSI (via testbench) IRQ: ", cnt_test); |
|
if (is_simulation) { // check if this is a simulation |
cnt_test++; |
907,7 → 907,7
// Machine external interrupt (MEI) via testbench |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] MEI (via testbench) IRQ test: ", cnt_test); |
neorv32_uart_printf("[%i] MEI (via testbench) IRQ: ", cnt_test); |
|
if (is_simulation) { // check if this is a simulation |
cnt_test++; |
1294,7 → 1294,7
// ---------------------------------------------------------- |
// Fast interrupt channel 9 (reserved) |
// ---------------------------------------------------------- |
neorv32_uart_printf("[%i] FIRQ9 test: ", cnt_test); |
neorv32_uart_printf("[%i] FIRQ9: ", cnt_test); |
neorv32_uart_printf("skipped (not implemented)\n"); |
|
|
1302,7 → 1302,7
// Fast interrupt channel 10..15 (SoC fast IRQ 0..5) |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] FIRQ10..15 (SoC fast IRQ 0..5; via testbench) test: ", cnt_test); |
neorv32_uart_printf("[%i] FIRQ10..15 (SoC fast IRQ 0..5; via testbench): ", cnt_test); |
|
if (is_simulation) { // check if this is a simulation |
|
1384,7 → 1384,7
// Test invalid CSR access in user mode |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] Invalid CSR access (mstatus) from user mode test: ", cnt_test); |
neorv32_uart_printf("[%i] Invalid CSR access (mstatus) from user mode: ", cnt_test); |
|
// skip if U-mode is not implemented |
if (neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_U_EXT)) { |
1420,7 → 1420,7
// Test RTE debug trap handler |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart_printf("[%i] RTE (runtime env.) debug trap handler test: ", cnt_test); |
neorv32_uart_printf("[%i] RTE (runtime env.) debug trap handler: ", cnt_test); |
|
cnt_test++; |
|
1474,7 → 1474,7
|
|
// ------ EXECUTE: should fail ------ |
neorv32_uart_printf("[%i] PMP: U-mode [!X,!W,R] execute test: ", cnt_test); |
neorv32_uart_printf("[%i] PMP: U-mode [!X,!W,R] execute: ", cnt_test); |
cnt_test++; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
|
1499,7 → 1499,7
|
|
// ------ LOAD: should work ------ |
neorv32_uart_printf("[%i] PMP: U-mode [!X,!W,R] read test: ", cnt_test); |
neorv32_uart_printf("[%i] PMP: U-mode [!X,!W,R] read: ", cnt_test); |
cnt_test++; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
|
1524,7 → 1524,7
|
|
// ------ STORE: should fail ------ |
neorv32_uart_printf("[%i] PMP: U-mode [!X,!W,R] write test: ", cnt_test); |
neorv32_uart_printf("[%i] PMP: U-mode [!X,!W,R] write: ", cnt_test); |
cnt_test++; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
|
1549,7 → 1549,7
|
|
// ------ Lock test - pmpcfg0.0 / pmpaddr0 ------ |
neorv32_uart_printf("[%i] PMP: Entry [mode=off] lock test: ", cnt_test); |
neorv32_uart_printf("[%i] PMP: Entry [mode=off] lock: ", cnt_test); |
cnt_test++; |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
|
1666,7 → 1666,7
neorv32_uart_printf("#08 - Store operations: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER8)); |
neorv32_uart_printf("#09 - Load/store wait cycles: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER9)); |
neorv32_uart_printf("#10 - Unconditional jumps: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER10)); |
neorv32_uart_printf("#11 - Cond. branches (all): %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER11)); |
neorv32_uart_printf("#11 - Cond. branches (total): %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER11)); |
neorv32_uart_printf("#12 - Cond. branches (taken): %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER12)); |
neorv32_uart_printf("#13 - Entered traps: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER13)); |
neorv32_uart_printf("#14 - Illegal operations: %u\n", (uint32_t)neorv32_cpu_csr_read(CSR_MHPMCOUNTER14)); |
/cpu_test/makefile
1,11 → 1,11
################################################################################################# |
# << NEORV32 - Application Makefile >> # |
# ********************************************************************************************* # |
# Make sure to add the riscv GCC compiler's bin folder to your PATH environment variable. # |
# Make sure to add the RISC-V GCC compiler's bin folder to your PATH environment variable. # |
# ********************************************************************************************* # |
# BSD 3-Clause License # |
# # |
# Copyright (c) 2020, Stephan Nolting. All rights reserved. # |
# Copyright (c) 2021, Stephan Nolting. All rights reserved. # |
# # |
# Redistribution and use in source and binary forms, with or without modification, are # |
# permitted provided that the following conditions are met: # |
126,7 → 126,7
IMAGE_GEN = $(NEORV32_EXG_PATH)/image_gen |
|
# Compiler & linker flags |
CC_OPTS = $(MARCH) $(MABI) $(EFFORT) -Wall -ffunction-sections -fdata-sections -nostartfiles |
CC_OPTS = $(MARCH) $(MABI) $(EFFORT) -Wall -ffunction-sections -fdata-sections -nostartfiles -mno-fdiv |
CC_OPTS += -Wl,--gc-sections -lm -lc -lgcc -lc |
# This accelerates instruction fetch after branches when C extension is enabled (irrelevant when C extension is disabled) |
CC_OPTS += -falign-functions=4 -falign-labels=4 -falign-loops=4 -falign-jumps=4 |
/demo_freeRTOS/makefile
1,11 → 1,11
################################################################################################# |
# << NEORV32 - Application Makefile >> # |
# ********************************************************************************************* # |
# Make sure to add the riscv GCC compiler's bin folder to your PATH environment variable. # |
# Make sure to add the RISC-V GCC compiler's bin folder to your PATH environment variable. # |
# ********************************************************************************************* # |
# BSD 3-Clause License # |
# # |
# Copyright (c) 2020, Stephan Nolting. All rights reserved. # |
# Copyright (c) 2021, Stephan Nolting. All rights reserved. # |
# # |
# Redistribution and use in source and binary forms, with or without modification, are # |
# permitted provided that the following conditions are met: # |
57,7 → 57,7
MABI ?= -mabi=ilp32 |
|
# User flags for additional configuration (will be added to compiler flags) |
USER_FLAGS ?= |
USER_FLAGS ?= |
|
# Serial port for executable upload via bootloer |
COM_PORT ?= /dev/ttyUSB0 |
69,79 → 69,6
|
|
# ----------------------------------------------------------------------------- |
# FreeRTOS |
# ----------------------------------------------------------------------------- |
ifneq (,$(findstring RUN_FREERTOS_DEMO,$(USER_FLAGS))) |
# FreeRTOS home folder (adapt this!) |
FREERTOS_HOME ?= /mnt/n/Projects/FreeRTOSv10.4.1 |
|
# FreeRTOS RISC-V specific |
APP_SRC += $(wildcard $(FREERTOS_HOME)/FreeRTOS/Source/portable/GCC/RISC-V/*.c) |
APP_SRC += $(FREERTOS_HOME)/FreeRTOS/Source/portable/GCC/RISC-V/portASM.S |
|
APP_INC += -I $(FREERTOS_HOME)/FreeRTOS/Source/portable/GCC/RISC-V |
|
# FreeRTOS core |
APP_SRC += $(wildcard $(FREERTOS_HOME)/FreeRTOS/Source/*.c) |
APP_SRC += $(wildcard $(FREERTOS_HOME)/FreeRTOS/Source/portable/MemMang/heap_4.c) |
|
APP_INC += -I $(FREERTOS_HOME)/FreeRTOS/Source/include |
|
# FreeRTOS sources for the full_demo |
APP_SRC += $(FREERTOS_HOME)/FreeRTOS/Demo/Common/Minimal/blocktim.c |
APP_SRC += $(FREERTOS_HOME)/FreeRTOS/Demo/Common/Minimal/dynamic.c |
APP_SRC += $(FREERTOS_HOME)/FreeRTOS/Demo/Common/Minimal/EventGroupsDemo.c |
APP_SRC += $(FREERTOS_HOME)/FreeRTOS/Demo/Common/Minimal/GenQTest.c |
APP_SRC += $(FREERTOS_HOME)/FreeRTOS/Demo/Common/Minimal/recmutex.c |
APP_SRC += $(FREERTOS_HOME)/FreeRTOS/Demo/Common/Minimal/TaskNotify.c |
APP_SRC += $(FREERTOS_HOME)/FreeRTOS/Demo/Common/Minimal/TaskNotifyArray.c |
APP_SRC += $(FREERTOS_HOME)/FreeRTOS/Demo/Common/Minimal/TimerDemo.c |
|
APP_INC += -I $(FREERTOS_HOME)/FreeRTOS/Demo/Common/include |
|
# NEORV32 specific |
ASM_INC += -DportasmHANDLE_INTERRUPT=SystemIrqHandler |
|
APP_INC += -I chip_specific_extensions/neorv32 |
|
ASM_INC += -I chip_specific_extensions/neorv32 |
|
# Demo application |
APP_SRC += blinky_demo/main_blinky.c |
APP_SRC += full_demo/main_full.c |
APP_SRC += full_demo/RegTest.s |
endif |
|
# ----------------- |
# FreeRTOS-Plus-CLI |
# ----------------- |
ifneq (,$(findstring FREERTOS_PLUS_CLI,$(USER_FLAGS))) |
APP_SRC += $(FREERTOS_HOME)/FreeRTOS-Plus/Source/FreeRTOS-Plus-CLI/FreeRTOS_CLI.c |
|
APP_INC += -I $(FREERTOS_HOME)/FreeRTOS-Plus/Source/FreeRTOS-Plus-CLI |
endif |
|
# ----------------- |
# FreeRTOS-Plus-TCP |
# ----------------- |
ifneq (,$(findstring FREERTOS_PLUS_TCP,$(USER_FLAGS))) |
APP_SRC += $(FREERTOS_HOME)/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_ARP.c |
APP_SRC += $(FREERTOS_HOME)/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_DHCP.c |
APP_SRC += $(FREERTOS_HOME)/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_DNS.c |
APP_SRC += $(FREERTOS_HOME)/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_IP.c |
APP_SRC += $(FREERTOS_HOME)/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_Sockets.c |
APP_SRC += $(FREERTOS_HOME)/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_Stream_Buffer.c |
APP_SRC += $(FREERTOS_HOME)/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_TCP_IP.c |
APP_SRC += $(FREERTOS_HOME)/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_TCP_WIN.c |
APP_SRC += $(FREERTOS_HOME)/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_UDP_IP.c |
|
APP_INC += -I $(FREERTOS_HOME)/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/include |
APP_INC += -I $(FREERTOS_HOME)/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/Compiler/GCC |
endif |
|
|
|
# ----------------------------------------------------------------------------- |
# NEORV32 framework |
# ----------------------------------------------------------------------------- |
# Path to NEORV32 linker script and startup file |
199,7 → 126,7
IMAGE_GEN = $(NEORV32_EXG_PATH)/image_gen |
|
# Compiler & linker flags |
CC_OPTS = $(MARCH) $(MABI) $(EFFORT) -Wall -ffunction-sections -fdata-sections -nostartfiles |
CC_OPTS = $(MARCH) $(MABI) $(EFFORT) -Wall -ffunction-sections -fdata-sections -nostartfiles -mno-fdiv |
CC_OPTS += -Wl,--gc-sections -lm -lc -lgcc -lc |
# This accelerates instruction fetch after branches when C extension is enabled (irrelevant when C extension is disabled) |
CC_OPTS += -falign-functions=4 -falign-labels=4 -falign-loops=4 -falign-jumps=4 |
/demo_gpio_irq/makefile
1,11 → 1,11
################################################################################################# |
# << NEORV32 - Application Makefile >> # |
# ********************************************************************************************* # |
# Make sure to add the riscv GCC compiler's bin folder to your PATH environment variable. # |
# Make sure to add the RISC-V GCC compiler's bin folder to your PATH environment variable. # |
# ********************************************************************************************* # |
# BSD 3-Clause License # |
# # |
# Copyright (c) 2020, Stephan Nolting. All rights reserved. # |
# Copyright (c) 2021, Stephan Nolting. All rights reserved. # |
# # |
# Redistribution and use in source and binary forms, with or without modification, are # |
# permitted provided that the following conditions are met: # |
126,7 → 126,7
IMAGE_GEN = $(NEORV32_EXG_PATH)/image_gen |
|
# Compiler & linker flags |
CC_OPTS = $(MARCH) $(MABI) $(EFFORT) -Wall -ffunction-sections -fdata-sections -nostartfiles |
CC_OPTS = $(MARCH) $(MABI) $(EFFORT) -Wall -ffunction-sections -fdata-sections -nostartfiles -mno-fdiv |
CC_OPTS += -Wl,--gc-sections -lm -lc -lgcc -lc |
# This accelerates instruction fetch after branches when C extension is enabled (irrelevant when C extension is disabled) |
CC_OPTS += -falign-functions=4 -falign-labels=4 -falign-loops=4 -falign-jumps=4 |
/demo_nco/makefile
1,11 → 1,11
################################################################################################# |
# << NEORV32 - Application Makefile >> # |
# ********************************************************************************************* # |
# Make sure to add the riscv GCC compiler's bin folder to your PATH environment variable. # |
# Make sure to add the RISC-V GCC compiler's bin folder to your PATH environment variable. # |
# ********************************************************************************************* # |
# BSD 3-Clause License # |
# # |
# Copyright (c) 2020, Stephan Nolting. All rights reserved. # |
# Copyright (c) 2021, Stephan Nolting. All rights reserved. # |
# # |
# Redistribution and use in source and binary forms, with or without modification, are # |
# permitted provided that the following conditions are met: # |
126,7 → 126,7
IMAGE_GEN = $(NEORV32_EXG_PATH)/image_gen |
|
# Compiler & linker flags |
CC_OPTS = $(MARCH) $(MABI) $(EFFORT) -Wall -ffunction-sections -fdata-sections -nostartfiles |
CC_OPTS = $(MARCH) $(MABI) $(EFFORT) -Wall -ffunction-sections -fdata-sections -nostartfiles -mno-fdiv |
CC_OPTS += -Wl,--gc-sections -lm -lc -lgcc -lc |
# This accelerates instruction fetch after branches when C extension is enabled (irrelevant when C extension is disabled) |
CC_OPTS += -falign-functions=4 -falign-labels=4 -falign-loops=4 -falign-jumps=4 |
/demo_neopixel/makefile
1,11 → 1,11
################################################################################################# |
# << NEORV32 - Application Makefile >> # |
# ********************************************************************************************* # |
# Make sure to add the riscv GCC compiler's bin folder to your PATH environment variable. # |
# Make sure to add the RISC-V GCC compiler's bin folder to your PATH environment variable. # |
# ********************************************************************************************* # |
# BSD 3-Clause License # |
# # |
# Copyright (c) 2020, Stephan Nolting. All rights reserved. # |
# Copyright (c) 2021, Stephan Nolting. All rights reserved. # |
# # |
# Redistribution and use in source and binary forms, with or without modification, are # |
# permitted provided that the following conditions are met: # |
126,7 → 126,7
IMAGE_GEN = $(NEORV32_EXG_PATH)/image_gen |
|
# Compiler & linker flags |
CC_OPTS = $(MARCH) $(MABI) $(EFFORT) -Wall -ffunction-sections -fdata-sections -nostartfiles |
CC_OPTS = $(MARCH) $(MABI) $(EFFORT) -Wall -ffunction-sections -fdata-sections -nostartfiles -mno-fdiv |
CC_OPTS += -Wl,--gc-sections -lm -lc -lgcc -lc |
# This accelerates instruction fetch after branches when C extension is enabled (irrelevant when C extension is disabled) |
CC_OPTS += -falign-functions=4 -falign-labels=4 -falign-loops=4 -falign-jumps=4 |
/demo_pwm/makefile
1,11 → 1,11
################################################################################################# |
# << NEORV32 - Application Makefile >> # |
# ********************************************************************************************* # |
# Make sure to add the riscv GCC compiler's bin folder to your PATH environment variable. # |
# Make sure to add the RISC-V GCC compiler's bin folder to your PATH environment variable. # |
# ********************************************************************************************* # |
# BSD 3-Clause License # |
# # |
# Copyright (c) 2020, Stephan Nolting. All rights reserved. # |
# Copyright (c) 2021, Stephan Nolting. All rights reserved. # |
# # |
# Redistribution and use in source and binary forms, with or without modification, are # |
# permitted provided that the following conditions are met: # |
126,7 → 126,7
IMAGE_GEN = $(NEORV32_EXG_PATH)/image_gen |
|
# Compiler & linker flags |
CC_OPTS = $(MARCH) $(MABI) $(EFFORT) -Wall -ffunction-sections -fdata-sections -nostartfiles |
CC_OPTS = $(MARCH) $(MABI) $(EFFORT) -Wall -ffunction-sections -fdata-sections -nostartfiles -mno-fdiv |
CC_OPTS += -Wl,--gc-sections -lm -lc -lgcc -lc |
# This accelerates instruction fetch after branches when C extension is enabled (irrelevant when C extension is disabled) |
CC_OPTS += -falign-functions=4 -falign-labels=4 -falign-loops=4 -falign-jumps=4 |
/demo_trng/makefile
1,11 → 1,11
################################################################################################# |
# << NEORV32 - Application Makefile >> # |
# ********************************************************************************************* # |
# Make sure to add the riscv GCC compiler's bin folder to your PATH environment variable. # |
# Make sure to add the RISC-V GCC compiler's bin folder to your PATH environment variable. # |
# ********************************************************************************************* # |
# BSD 3-Clause License # |
# # |
# Copyright (c) 2020, Stephan Nolting. All rights reserved. # |
# Copyright (c) 2021, Stephan Nolting. All rights reserved. # |
# # |
# Redistribution and use in source and binary forms, with or without modification, are # |
# permitted provided that the following conditions are met: # |
126,7 → 126,7
IMAGE_GEN = $(NEORV32_EXG_PATH)/image_gen |
|
# Compiler & linker flags |
CC_OPTS = $(MARCH) $(MABI) $(EFFORT) -Wall -ffunction-sections -fdata-sections -nostartfiles |
CC_OPTS = $(MARCH) $(MABI) $(EFFORT) -Wall -ffunction-sections -fdata-sections -nostartfiles -mno-fdiv |
CC_OPTS += -Wl,--gc-sections -lm -lc -lgcc -lc |
# This accelerates instruction fetch after branches when C extension is enabled (irrelevant when C extension is disabled) |
CC_OPTS += -falign-functions=4 -falign-labels=4 -falign-loops=4 -falign-jumps=4 |
/demo_twi/makefile
1,11 → 1,11
################################################################################################# |
# << NEORV32 - Application Makefile >> # |
# ********************************************************************************************* # |
# Make sure to add the riscv GCC compiler's bin folder to your PATH environment variable. # |
# Make sure to add the RISC-V GCC compiler's bin folder to your PATH environment variable. # |
# ********************************************************************************************* # |
# BSD 3-Clause License # |
# # |
# Copyright (c) 2020, Stephan Nolting. All rights reserved. # |
# Copyright (c) 2021, Stephan Nolting. All rights reserved. # |
# # |
# Redistribution and use in source and binary forms, with or without modification, are # |
# permitted provided that the following conditions are met: # |
126,7 → 126,7
IMAGE_GEN = $(NEORV32_EXG_PATH)/image_gen |
|
# Compiler & linker flags |
CC_OPTS = $(MARCH) $(MABI) $(EFFORT) -Wall -ffunction-sections -fdata-sections -nostartfiles |
CC_OPTS = $(MARCH) $(MABI) $(EFFORT) -Wall -ffunction-sections -fdata-sections -nostartfiles -mno-fdiv |
CC_OPTS += -Wl,--gc-sections -lm -lc -lgcc -lc |
# This accelerates instruction fetch after branches when C extension is enabled (irrelevant when C extension is disabled) |
CC_OPTS += -falign-functions=4 -falign-labels=4 -falign-loops=4 -falign-jumps=4 |
/demo_wdt/makefile
1,11 → 1,11
################################################################################################# |
# << NEORV32 - Application Makefile >> # |
# ********************************************************************************************* # |
# Make sure to add the riscv GCC compiler's bin folder to your PATH environment variable. # |
# Make sure to add the RISC-V GCC compiler's bin folder to your PATH environment variable. # |
# ********************************************************************************************* # |
# BSD 3-Clause License # |
# # |
# Copyright (c) 2020, Stephan Nolting. All rights reserved. # |
# Copyright (c) 2021, Stephan Nolting. All rights reserved. # |
# # |
# Redistribution and use in source and binary forms, with or without modification, are # |
# permitted provided that the following conditions are met: # |
126,7 → 126,7
IMAGE_GEN = $(NEORV32_EXG_PATH)/image_gen |
|
# Compiler & linker flags |
CC_OPTS = $(MARCH) $(MABI) $(EFFORT) -Wall -ffunction-sections -fdata-sections -nostartfiles |
CC_OPTS = $(MARCH) $(MABI) $(EFFORT) -Wall -ffunction-sections -fdata-sections -nostartfiles -mno-fdiv |
CC_OPTS += -Wl,--gc-sections -lm -lc -lgcc -lc |
# This accelerates instruction fetch after branches when C extension is enabled (irrelevant when C extension is disabled) |
CC_OPTS += -falign-functions=4 -falign-labels=4 -falign-loops=4 -falign-jumps=4 |
/floating_point_test/README.md
0,0 → 1,38
# NEORV32 `Zfinx` Floating-Point Extension |
|
The RISC-V `Zfinx` single-precision floating-point extensions uses the integer register file `x` instead of the dedicated floating-point `f` register file (which is |
defined by the RISC-V `F` single-precision floating-point extension). Hence, the standard data transfer instructions from the `F` extension are **not** available in `Zfinx`: |
|
* floating-point load/store operations (`FLW`, `FSW`) and their compressed versions |
* integer register file `x` <-> floating point register file `f` move operations (`FMV.W.X`, `FMV.X.W`) |
|
|
:information_source: More information regarding the RISC-V `Zfinx` single-precision floating-point extension can be found in the officail GitHub repo: |
[`github.com/riscv/riscv-zfinx`](https://github.com/riscv/riscv-zfinx). |
|
:warning: The RISC-V `Zfinx` extension is not officially ratified yet, but it is assumed to remain unchanged. Hence, it is not supported by the upstream RISC-V GCC port. |
Make sure you **do not** use the `f` ISA attribute when compiling applications that use floating-point arithmetic (`-march=rv32i*f*` is **NOT ALLOWED!**). |
|
|
## Intrinsic Library |
|
The NEORV32 `Zfinx` floating-point extension can still be used using the provided **intrinsic library**. This library uses "custom" inline assmbly instructions |
wrapped within normal C-language functions. Each original instruction of the extension can be utilized using an according intrinsic function. |
|
For example, the floating-point addition instruction `FADD.S` can be invoked using the according intrinsic function: |
|
```c |
float riscv_intrinsic_fadds(float rs1, float rs2) |
``` |
|
The pure-software emulation instruction, which uses the standard builtin functions to execute all floating-point operations, is available via wrapper function. The |
emulation function for the `FADD.S` instruction is: |
|
```c |
float riscv_emulate_fadds(float rs1, float rs2) |
``` |
|
The emulation functions as well as the available intrinsics for the `Zfinx` extension are located in `neorv32_zfinx_extension_intrinsics.h`. |
|
The provided test program `main.c` verifies all currently implemented `Zfinx` instructions by checking the functionality against the pure software-based emulation model |
(GCC soft-float library). |
/floating_point_test/main.c
0,0 → 1,604
// ################################################################################################# |
// # << NEORV32 - RISC-V Single-Precision Floating-Point 'Zfinx' Extension Verification Program >> # |
// # ********************************************************************************************* # |
// # BSD 3-Clause License # |
// # # |
// # Copyright (c) 2021, Stephan Nolting. All rights reserved. # |
// # # |
// # Redistribution and use in source and binary forms, with or without modification, are # |
// # permitted provided that the following conditions are met: # |
// # # |
// # 1. Redistributions of source code must retain the above copyright notice, this list of # |
// # conditions and the following disclaimer. # |
// # # |
// # 2. Redistributions in binary form must reproduce the above copyright notice, this list of # |
// # conditions and the following disclaimer in the documentation and/or other materials # |
// # provided with the distribution. # |
// # # |
// # 3. Neither the name of the copyright holder nor the names of its contributors may be used to # |
// # endorse or promote products derived from this software without specific prior written # |
// # permission. # |
// # # |
// # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS # |
// # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # |
// # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # |
// # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # |
// # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE # |
// # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED # |
// # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # |
// # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # |
// # OF THE POSSIBILITY OF SUCH DAMAGE. # |
// # ********************************************************************************************* # |
// # The NEORV32 Processor - https://github.com/stnolting/neorv32 (c) Stephan Nolting # |
// ################################################################################################# |
|
|
/**********************************************************************//** |
* @file floating_point_test/main.c |
* @author Stephan Nolting |
* @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. |
**************************************************************************/ |
|
#include <neorv32.h> |
#include <float.h> |
#include <math.h> |
#include "neorv32_zfinx_extension_intrinsics.h" |
|
#ifdef NAN |
/* NAN is supported */ |
#else |
#warning NAN macro not supported! |
#endif |
#ifdef INFINITY |
/* INFINITY is supported */ |
#else |
#warning INFINITY macro not supported! |
#endif |
|
|
/**********************************************************************//** |
* @name User configuration |
**************************************************************************/ |
/**@{*/ |
/** UART BAUD rate */ |
#define BAUD_RATE (19200) |
//** Number of test cases for each instruction */ |
#define NUM_TEST_CASES (1000000) |
//** Silent mode (only show actual errors when != 0) */ |
#define SILENT_MODE (1) |
//** Run conversion tests when != 0 */ |
#define RUN_CONV_TESTS (1) |
//** Run add/sub tests when != 0 */ |
#define RUN_ADDSUB_TESTS (1) |
//** Run multiplication tests when != 0 */ |
#define RUN_MUL_TESTS (1) |
//** Run min/max tests when != 0 */ |
#define RUN_MINMAX_TESTS (1) |
//** Run comparison tests when != 0 */ |
#define RUN_COMPARE_TESTS (1) |
//** Run sign-injection tests when != 0 */ |
#define RUN_SGNINJ_TESTS (1) |
//** Run classify tests when != 0 */ |
#define RUN_CLASSIFY_TESTS (1) |
//** Run unsupported instructions tests when != 0 */ |
#define RUN_UNAVAIL_TESTS (1) |
/**@}*/ |
|
|
// Prototypes |
uint32_t get_test_vector(void); |
uint32_t xorshift32(void); |
uint32_t verify_result(uint32_t num, uint32_t opa, uint32_t opb, uint32_t ref, uint32_t res); |
void print_report(uint32_t num_err); |
|
|
/**********************************************************************//** |
* Main function; test all available operations of the NEORV32 'Zfinx' extensions using bit floating-point hardware intrinsics and software-only reference functions (emulation). |
* |
* @note This program requires the Zfinx CPU extension. |
* |
* @return Irrelevant. |
**************************************************************************/ |
int main() { |
|
uint32_t err_cnt = 0; |
uint32_t err_cnt_total = 0; |
uint32_t test_cnt = 0; |
uint32_t i = 0; |
float_conv_t opa; |
float_conv_t opb; |
float_conv_t res_hw; |
float_conv_t res_sw; |
|
|
// init primary UART |
neorv32_uart_setup(BAUD_RATE, PARITY_NONE, FLOW_CONTROL_NONE); |
|
// capture all exceptions and give debug info via UART |
neorv32_rte_setup(); |
|
// check available hardware extensions and compare with compiler flags |
neorv32_rte_check_isa(0); // silent = 0 -> show message if isa mismatch |
|
// check if Zfinx extension is implemented at all |
if (neorv32_check_zextension(CSR_MZEXT_ZFINX) == 0) { |
neorv32_uart_print("Error! <Zfinx> extension not synthesized!\n"); |
return 0; |
} |
|
|
// Disable compilation by default |
#ifndef RUN_TEST |
#warning Program HAS NOT BEEN COMPILED! Use >>make USER_FLAGS+=-DRUN_TEST clean_all exe<< to compile it. |
|
// inform the user if you are actually executing this |
neorv32_uart_printf("ERROR! Program has not been compiled. Use >>make USER_FLAGS+=-DRUN_TEST clean_all exe<< to compile it.\n"); |
|
return 0; |
#endif |
|
|
// intro |
neorv32_uart_printf("<<< Zfinx extension test >>>\n"); |
#if (SILENT_MODE != 0) |
neorv32_uart_printf("SILENT_MODE enabled (only showing actual errors)\n"); |
#endif |
neorv32_uart_printf("Test cases per instruction: %u\n\n", (uint32_t)NUM_TEST_CASES); |
|
|
// clear exception status word |
neorv32_cpu_csr_write(CSR_FFLAGS, 0);; // real hardware |
feclearexcept(FE_ALL_EXCEPT); // software runtime (GCC floating-point emulation) |
|
|
// ---------------------------------------------------------------------------- |
// Conversion Tests |
// ---------------------------------------------------------------------------- |
|
#if (RUN_CONV_TESTS != 0) |
neorv32_uart_printf("\n#%u: FCVT.S.WU (unsigned integer to float)...\n", test_cnt); |
err_cnt = 0; |
for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) { |
opa.binary_value = get_test_vector(); |
res_hw.float_value = riscv_intrinsic_fcvt_swu(opa.binary_value); |
res_sw.float_value = riscv_emulate_fcvt_swu(opa.binary_value); |
err_cnt += verify_result(i, opa.binary_value, 0, res_sw.binary_value, res_hw.binary_value); |
} |
print_report(err_cnt); |
err_cnt_total += err_cnt; |
test_cnt++; |
|
neorv32_uart_printf("\n#%u: FCVT.S.W (signed integer to float)...\n", test_cnt); |
err_cnt = 0; |
for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) { |
opa.binary_value = get_test_vector(); |
res_hw.float_value = riscv_intrinsic_fcvt_sw((int32_t)opa.binary_value); |
res_sw.float_value = riscv_emulate_fcvt_sw((int32_t)opa.binary_value); |
err_cnt += verify_result(i, opa.binary_value, 0, res_sw.binary_value, res_hw.binary_value); |
} |
print_report(err_cnt); |
err_cnt_total += err_cnt; |
test_cnt++; |
|
neorv32_uart_printf("\n#%u: FCVT.WU.S (float to unsigned integer)...\n", test_cnt); |
err_cnt = 0; |
for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) { |
opa.binary_value = get_test_vector(); |
res_hw.binary_value = riscv_intrinsic_fcvt_wus(opa.float_value); |
res_sw.binary_value = riscv_emulate_fcvt_wus(opa.float_value); |
err_cnt += verify_result(i, opa.binary_value, 0, res_sw.binary_value, res_hw.binary_value); |
} |
print_report(err_cnt); |
err_cnt_total += err_cnt; |
test_cnt++; |
|
neorv32_uart_printf("\n#%u: FCVT.W.S (float to signed integer)...\n", test_cnt); |
err_cnt = 0; |
for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) { |
opa.binary_value = get_test_vector(); |
res_hw.binary_value = (uint32_t)riscv_intrinsic_fcvt_ws(opa.float_value); |
res_sw.binary_value = (uint32_t)riscv_emulate_fcvt_ws(opa.float_value); |
err_cnt += verify_result(i, opa.binary_value, 0, res_sw.binary_value, res_hw.binary_value); |
} |
print_report(err_cnt); |
err_cnt_total += err_cnt; |
test_cnt++; |
#endif |
|
|
// ---------------------------------------------------------------------------- |
// Add/Sub Tests |
// ---------------------------------------------------------------------------- |
|
#if (RUN_ADDSUB_TESTS != 0) |
neorv32_uart_printf("\n#%u: FADD.S (addition)...\n", test_cnt); |
err_cnt = 0; |
for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) { |
opa.binary_value = get_test_vector(); |
opb.binary_value = get_test_vector(); |
res_hw.float_value = riscv_intrinsic_fadds(opa.float_value, opb.float_value); |
res_sw.float_value = riscv_emulate_fadds(opa.float_value, opb.float_value); |
err_cnt += verify_result(i, opa.binary_value, opb.binary_value, res_sw.binary_value, res_hw.binary_value); |
} |
print_report(err_cnt); |
err_cnt_total += err_cnt; |
test_cnt++; |
|
neorv32_uart_printf("\n#%u: FSUB.S (subtraction)...\n", test_cnt); |
err_cnt = 0; |
for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) { |
opa.binary_value = get_test_vector(); |
opb.binary_value = get_test_vector(); |
res_hw.float_value = riscv_intrinsic_fsubs(opa.float_value, opb.float_value); |
res_sw.float_value = riscv_emulate_fsubs(opa.float_value, opb.float_value); |
err_cnt += verify_result(i, opa.binary_value, opb.binary_value, res_sw.binary_value, res_hw.binary_value); |
} |
print_report(err_cnt); |
err_cnt_total += err_cnt; |
test_cnt++; |
#endif |
|
|
// ---------------------------------------------------------------------------- |
// Multiplication Tests |
// ---------------------------------------------------------------------------- |
|
#if (RUN_MUL_TESTS != 0) |
neorv32_uart_printf("\n#%u: FMUL.S (multiplication)...\n", test_cnt); |
err_cnt = 0; |
for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) { |
opa.binary_value = get_test_vector(); |
opb.binary_value = get_test_vector(); |
res_hw.float_value = riscv_intrinsic_fmuls(opa.float_value, opb.float_value); |
res_sw.float_value = riscv_emulate_fmuls(opa.float_value, opb.float_value); |
err_cnt += verify_result(i, opa.binary_value, opb.binary_value, res_sw.binary_value, res_hw.binary_value); |
} |
print_report(err_cnt); |
err_cnt_total += err_cnt; |
test_cnt++; |
#endif |
|
|
// ---------------------------------------------------------------------------- |
// Min/Max Tests |
// ---------------------------------------------------------------------------- |
|
#if (RUN_MINMAX_TESTS != 0) |
neorv32_uart_printf("\n#%u: FMIN.S (select minimum)...\n", test_cnt); |
err_cnt = 0; |
for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) { |
opa.binary_value = get_test_vector(); |
opb.binary_value = get_test_vector(); |
res_hw.float_value = riscv_intrinsic_fmins(opa.float_value, opb.float_value); |
res_sw.float_value = riscv_emulate_fmins(opa.float_value, opb.float_value); |
err_cnt += verify_result(i, opa.binary_value, opb.binary_value, res_sw.binary_value, res_hw.binary_value); |
} |
print_report(err_cnt); |
err_cnt_total += err_cnt; |
test_cnt++; |
|
neorv32_uart_printf("\n#%u: FMAX.S (select maximum)...\n", test_cnt); |
err_cnt = 0; |
for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) { |
opa.binary_value = get_test_vector(); |
opb.binary_value = get_test_vector(); |
res_hw.float_value = riscv_intrinsic_fmaxs(opa.float_value, opb.float_value); |
res_sw.float_value = riscv_emulate_fmaxs(opa.float_value, opb.float_value); |
err_cnt += verify_result(i, opa.binary_value, opb.binary_value, res_sw.binary_value, res_hw.binary_value); |
} |
print_report(err_cnt); |
err_cnt_total += err_cnt; |
test_cnt++; |
#endif |
|
|
// ---------------------------------------------------------------------------- |
// Comparison Tests |
// ---------------------------------------------------------------------------- |
|
#if (RUN_COMPARE_TESTS != 0) |
neorv32_uart_printf("\n#%u: FEQ.S (compare if equal)...\n", test_cnt); |
err_cnt = 0; |
for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) { |
opa.binary_value = get_test_vector(); |
opb.binary_value = get_test_vector(); |
res_hw.binary_value = riscv_intrinsic_feqs(opa.float_value, opb.float_value); |
res_sw.binary_value = riscv_emulate_feqs(opa.float_value, opb.float_value); |
err_cnt += verify_result(i, opa.binary_value, opb.binary_value, res_sw.binary_value, res_hw.binary_value); |
} |
print_report(err_cnt); |
err_cnt_total += err_cnt; |
test_cnt++; |
|
neorv32_uart_printf("\n#%u: FLT.S (compare if less-than)...\n", test_cnt); |
err_cnt = 0; |
for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) { |
opa.binary_value = get_test_vector(); |
opb.binary_value = get_test_vector(); |
res_hw.binary_value = riscv_intrinsic_flts(opa.float_value, opb.float_value); |
res_sw.binary_value = riscv_emulate_flts(opa.float_value, opb.float_value); |
err_cnt += verify_result(i, opa.binary_value, opb.binary_value, res_sw.binary_value, res_hw.binary_value); |
} |
print_report(err_cnt); |
err_cnt_total += err_cnt; |
test_cnt++; |
|
neorv32_uart_printf("\n#%u: FLE.S (compare if less-than-or-equal)...\n", test_cnt); |
err_cnt = 0; |
for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) { |
opa.binary_value = get_test_vector(); |
opb.binary_value = get_test_vector(); |
res_hw.binary_value = riscv_intrinsic_fles(opa.float_value, opb.float_value); |
res_sw.binary_value = riscv_emulate_fles(opa.float_value, opb.float_value); |
err_cnt += verify_result(i, opa.binary_value, opb.binary_value, res_sw.binary_value, res_hw.binary_value); |
} |
print_report(err_cnt); |
err_cnt_total += err_cnt; |
test_cnt++; |
#endif |
|
|
// ---------------------------------------------------------------------------- |
// Sign-Injection Tests |
// ---------------------------------------------------------------------------- |
|
#if (RUN_SGNINJ_TESTS != 0) |
neorv32_uart_printf("\n#%u: FSGNJ.S (sign-injection)...\n", test_cnt); |
err_cnt = 0; |
for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) { |
opa.binary_value = get_test_vector(); |
opb.binary_value = get_test_vector(); |
res_hw.float_value = riscv_intrinsic_fsgnjs(opa.float_value, opb.float_value); |
res_sw.float_value = riscv_emulate_fsgnjs(opa.float_value, opb.float_value); |
err_cnt += verify_result(i, opa.binary_value, opb.binary_value, res_sw.binary_value, res_hw.binary_value); |
} |
print_report(err_cnt); |
err_cnt_total += err_cnt; |
test_cnt++; |
|
neorv32_uart_printf("\n#%u: FSGNJN.S (sign-injection NOT)...\n", test_cnt); |
err_cnt = 0; |
for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) { |
opa.binary_value = get_test_vector(); |
opb.binary_value = get_test_vector(); |
res_hw.float_value = riscv_intrinsic_fsgnjns(opa.float_value, opb.float_value); |
res_sw.float_value = riscv_emulate_fsgnjns(opa.float_value, opb.float_value); |
err_cnt += verify_result(i, opa.binary_value, opb.binary_value, res_sw.binary_value, res_hw.binary_value); |
} |
print_report(err_cnt); |
err_cnt_total += err_cnt; |
test_cnt++; |
|
neorv32_uart_printf("\n#%u: FSGNJX.S (sign-injection XOR)...\n", test_cnt); |
err_cnt = 0; |
for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) { |
opa.binary_value = get_test_vector(); |
opb.binary_value = get_test_vector(); |
res_hw.float_value = riscv_intrinsic_fsgnjxs(opa.float_value, opb.float_value); |
res_sw.float_value = riscv_emulate_fsgnjxs(opa.float_value, opb.float_value); |
err_cnt += verify_result(i, opa.binary_value, opb.binary_value, res_sw.binary_value, res_hw.binary_value); |
} |
print_report(err_cnt); |
err_cnt_total += err_cnt; |
test_cnt++; |
#endif |
|
|
// ---------------------------------------------------------------------------- |
// Classify Tests |
// ---------------------------------------------------------------------------- |
|
#if (RUN_CLASSIFY_TESTS != 0) |
neorv32_uart_printf("\n#%u: FCLASS.S (classify)...\n", test_cnt); |
err_cnt = 0; |
for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) { |
opa.binary_value = get_test_vector(); |
res_hw.binary_value = riscv_intrinsic_fclasss(opa.float_value); |
res_sw.binary_value = riscv_emulate_fclasss(opa.float_value); |
err_cnt += verify_result(i, opa.binary_value, 0, res_sw.binary_value, res_hw.binary_value); |
} |
print_report(err_cnt); |
err_cnt_total += err_cnt; |
test_cnt++; |
#endif |
|
|
// ---------------------------------------------------------------------------- |
// UNSUPPORTED Instructions Tests - Execution should raise illegal instruction exception |
// ---------------------------------------------------------------------------- |
|
#if (RUN_UNAVAIL_TESTS != 0) |
neorv32_uart_printf("\n# unsupported FDIV.S (division) [illegal instruction]...\n"); |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
opa.binary_value = get_test_vector(); |
opb.binary_value = get_test_vector(); |
riscv_intrinsic_fdivs(opa.float_value, opb.float_value); |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) { |
neorv32_uart_printf("%c[1m[FAILED]%c[0m\n", 27, 27); |
err_cnt_total++; |
} |
else { |
neorv32_uart_printf("%c[1m[ok]%c[0m\n", 27, 27); |
} |
|
neorv32_uart_printf("\n# unsupported FSQRT.S (square root) [illegal instruction]...\n"); |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
opa.binary_value = get_test_vector(); |
opb.binary_value = get_test_vector(); |
riscv_intrinsic_fsqrts(opa.float_value); |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) { |
neorv32_uart_printf("%c[1m[FAILED]%c[0m\n", 27, 27); |
err_cnt_total++; |
} |
else { |
neorv32_uart_printf("%c[1m[ok]%c[0m\n", 27, 27); |
} |
|
neorv32_uart_printf("\n# unsupported FMADD.S (fused multiply-add) [illegal instruction]...\n"); |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
opa.binary_value = get_test_vector(); |
opb.binary_value = get_test_vector(); |
riscv_intrinsic_fmadds(opa.float_value, opb.float_value, -opa.float_value); |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) { |
neorv32_uart_printf("%c[1m[FAILED]%c[0m\n", 27, 27); |
err_cnt_total++; |
} |
else { |
neorv32_uart_printf("%c[1m[ok]%c[0m\n", 27, 27); |
} |
|
neorv32_uart_printf("\n# unsupported FMSUB.S (fused multiply-sub) [illegal instruction]...\n"); |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
opa.binary_value = get_test_vector(); |
opb.binary_value = get_test_vector(); |
riscv_intrinsic_fmsubs(opa.float_value, opb.float_value, -opa.float_value); |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) { |
neorv32_uart_printf("%c[1m[FAILED]%c[0m\n", 27, 27); |
err_cnt_total++; |
} |
else { |
neorv32_uart_printf("%c[1m[ok]%c[0m\n", 27, 27); |
} |
|
neorv32_uart_printf("\n# unsupported FNMSUB.S (fused negated multiply-sub) [illegal instruction]...\n"); |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
opa.binary_value = get_test_vector(); |
opb.binary_value = get_test_vector(); |
riscv_intrinsic_fnmadds(opa.float_value, opb.float_value, -opa.float_value); |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) { |
neorv32_uart_printf("%c[1m[FAILED]%c[0m\n", 27, 27); |
err_cnt_total++; |
} |
else { |
neorv32_uart_printf("%c[1m[ok]%c[0m\n", 27, 27); |
} |
|
neorv32_uart_printf("\n# unsupported FNMADD.S (fused negated multiply-add) [illegal instruction]...\n"); |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
opa.binary_value = get_test_vector(); |
opb.binary_value = get_test_vector(); |
riscv_intrinsic_fnmadds(opa.float_value, opb.float_value, -opa.float_value); |
if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) { |
neorv32_uart_printf("%c[1m[FAILED]%c[0m\n", 27, 27); |
err_cnt_total++; |
} |
else { |
neorv32_uart_printf("%c[1m[ok]%c[0m\n", 27, 27); |
} |
#endif |
|
|
// final report |
if (err_cnt_total != 0) { |
neorv32_uart_printf("\n%c[1m[ZFINX EXTENSION VERIFICATION FAILED!]%c[0m\n", 27, 27); |
neorv32_uart_printf("%u errors in %u test cases\n", err_cnt_total, test_cnt*(uint32_t)NUM_TEST_CASES); |
} |
else { |
neorv32_uart_printf("\n%c[1m[Zfinx extension verification successful!]%c[0m\n", 27, 27); |
} |
|
return 0; |
} |
|
|
/**********************************************************************//** |
* Generate 32-bit test data (including special values like INFINITY every now and then). |
* |
* @return Test data (32-bit). |
**************************************************************************/ |
uint32_t get_test_vector(void) { |
|
float_conv_t tmp; |
|
// generate special value "every" ~256th time this function is called |
if ((xorshift32() & 0xff) == 0xff) { |
|
switch((xorshift32() >> 10) & 0x3) { // random decision which special value we are taking |
case 0: tmp.float_value = +INFINITY; break; |
case 1: tmp.float_value = -INFINITY; break; |
case 2: tmp.float_value = +0.0f; break; |
case 3: tmp.float_value = -0.0f; break; |
case 4: tmp.binary_value = 0x7fffffff; break; |
case 5: tmp.binary_value = 0xffffffff; break; |
case 6: tmp.float_value = NAN; break; |
case 7: tmp.float_value = NAN; break; // FIXME signaling_NAN? |
default: tmp.float_value = NAN; break; |
} |
} |
else { |
tmp.binary_value = xorshift32(); |
} |
|
// subnormal numbers are not supported yet! |
// flush them to zero |
//tmp.float_value = subnormal_flush(tmp.float_value); |
|
return tmp.binary_value; |
} |
|
|
/**********************************************************************//** |
* PSEUDO-RANDOM number generator. |
* |
* @return Random data (32-bit). |
**************************************************************************/ |
uint32_t xorshift32(void) { |
|
static uint32_t x32 = 314159265; |
|
x32 ^= x32 << 13; |
x32 ^= x32 >> 17; |
x32 ^= x32 << 5; |
|
return x32; |
} |
|
|
/**********************************************************************//** |
* Verify results (software reference vs. actual hardware). |
* |
* @param[in] num Test case number |
* @param[in] opa Operand 1 |
* @param[in] opb Operand 2 |
* @param[in] ref Software reference |
* @param[in] res Actual results from hardware |
* @return zero if results are equal. |
**************************************************************************/ |
uint32_t verify_result(uint32_t num, uint32_t opa, uint32_t opb, uint32_t ref, uint32_t res) { |
|
#if (SILENT_MODE == 0) |
neorv32_uart_printf("%u: opa = 0x%x, opb = 0x%x : ref[SW] = 0x%x vs. res[HW] = 0x%x ", num, opa, opb, ref, res); |
#endif |
|
if (ref != res) { |
#if (SILENT_MODE != 0) |
neorv32_uart_printf("%u: opa = 0x%x, opb = 0x%x : ref[SW] = 0x%x vs. res[HW] = 0x%x ", num, opa, opb, ref, res); |
#endif |
neorv32_uart_printf("%c[1m[FAILED]%c[0m\n", 27, 27); |
return 1; |
} |
else { |
#if (SILENT_MODE == 0) |
neorv32_uart_printf("%c[1m[ok]%c[0m\n", 27, 27); |
#endif |
return 0; |
} |
} |
|
|
/**********************************************************************//** |
* Print test report. |
* |
* @param[in] num_err Number or errors in this test. |
**************************************************************************/ |
void print_report(uint32_t num_err) { |
|
neorv32_uart_printf("Errors: %u/%u ", num_err, (uint32_t)NUM_TEST_CASES); |
|
if (num_err == 0) { |
neorv32_uart_printf("%c[1m[ok]%c[0m\n", 27, 27); |
} |
else { |
neorv32_uart_printf("%c[1m[FAILED]%c[0m\n", 27, 27); |
} |
} |
/floating_point_test/makefile
0,0 → 1,338
################################################################################################# |
# << NEORV32 - Application Makefile >> # |
# ********************************************************************************************* # |
# Make sure to add the RISC-V GCC compiler's bin folder to your PATH environment variable. # |
# ********************************************************************************************* # |
# BSD 3-Clause License # |
# # |
# Copyright (c) 2021, Stephan Nolting. All rights reserved. # |
# # |
# Redistribution and use in source and binary forms, with or without modification, are # |
# permitted provided that the following conditions are met: # |
# # |
# 1. Redistributions of source code must retain the above copyright notice, this list of # |
# conditions and the following disclaimer. # |
# # |
# 2. Redistributions in binary form must reproduce the above copyright notice, this list of # |
# conditions and the following disclaimer in the documentation and/or other materials # |
# provided with the distribution. # |
# # |
# 3. Neither the name of the copyright holder nor the names of its contributors may be used to # |
# endorse or promote products derived from this software without specific prior written # |
# permission. # |
# # |
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS # |
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # |
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # |
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # |
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE # |
# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED # |
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # |
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # |
# OF THE POSSIBILITY OF SUCH DAMAGE. # |
# ********************************************************************************************* # |
# The NEORV32 Processor - https://github.com/stnolting/neorv32 (c) Stephan Nolting # |
################################################################################################# |
|
|
# ***************************************************************************** |
# USER CONFIGURATION |
# ***************************************************************************** |
# User's application sources (*.c, *.cpp, *.s, *.S); add additional files here |
APP_SRC ?= $(wildcard ./*.c) $(wildcard ./*.s) $(wildcard ./*.cpp) $(wildcard ./*.S) |
|
# User's application include folders (don't forget the '-I' before each entry) |
APP_INC ?= -I . |
# User's application include folders - for assembly files only (don't forget the '-I' before each entry) |
ASM_INC ?= -I . |
|
# Optimization |
EFFORT ?= -Os |
|
# Compiler toolchain |
RISCV_TOOLCHAIN ?= riscv32-unknown-elf |
|
# CPU architecture and ABI |
MARCH ?= -march=rv32i |
MABI ?= -mabi=ilp32 |
|
# User flags for additional configuration (will be added to compiler flags) |
USER_FLAGS ?= |
|
# Serial port for executable upload via bootloer |
COM_PORT ?= /dev/ttyUSB0 |
|
# Relative or absolute path to the NEORV32 home folder |
NEORV32_HOME ?= ../../.. |
# ***************************************************************************** |
|
|
|
# ----------------------------------------------------------------------------- |
# NEORV32 framework |
# ----------------------------------------------------------------------------- |
# Path to NEORV32 linker script and startup file |
NEORV32_COM_PATH = $(NEORV32_HOME)/sw/common |
# Path to main NEORV32 library include files |
NEORV32_INC_PATH = $(NEORV32_HOME)/sw/lib/include |
# Path to main NEORV32 library source files |
NEORV32_SRC_PATH = $(NEORV32_HOME)/sw/lib/source |
# Path to NEORV32 executable generator |
NEORV32_EXG_PATH = $(NEORV32_HOME)/sw/image_gen |
# Path to NEORV32 core rtl folder |
NEORV32_RTL_PATH = $(NEORV32_HOME)/rtl/core |
# Marker file to check for NEORV32 home folder |
NEORV32_HOME_MARKER = $(NEORV32_INC_PATH)/neorv32.h |
|
# Core libraries (peripheral and CPU drivers) |
CORE_SRC = $(wildcard $(NEORV32_SRC_PATH)/*.c) |
# Application start-up code |
CORE_SRC += $(NEORV32_COM_PATH)/crt0.S |
|
# Linker script |
LD_SCRIPT = $(NEORV32_COM_PATH)/neorv32.ld |
|
# Main output files |
APP_EXE = neorv32_exe.bin |
APP_ASM = main.asm |
APP_IMG = neorv32_application_image.vhd |
BOOT_IMG = neorv32_bootloader_image.vhd |
|
|
# ----------------------------------------------------------------------------- |
# Sources and objects |
# ----------------------------------------------------------------------------- |
# Define all sources |
SRC = $(APP_SRC) |
SRC += $(CORE_SRC) |
|
# Define all object files |
OBJ = $(SRC:%=%.o) |
|
|
# ----------------------------------------------------------------------------- |
# Tools and flags |
# ----------------------------------------------------------------------------- |
# Compiler tools |
CC = $(RISCV_TOOLCHAIN)-gcc |
OBJDUMP = $(RISCV_TOOLCHAIN)-objdump |
OBJCOPY = $(RISCV_TOOLCHAIN)-objcopy |
SIZE = $(RISCV_TOOLCHAIN)-size |
|
# Host native compiler |
CC_X86 = g++ -Wall -O -g |
|
# NEORV32 executable image generator |
IMAGE_GEN = $(NEORV32_EXG_PATH)/image_gen |
|
# Compiler & linker flags |
CC_OPTS = $(MARCH) $(MABI) $(EFFORT) -Wall -ffunction-sections -fdata-sections -nostartfiles -mno-fdiv |
CC_OPTS += -Wl,--gc-sections -lm -lc -lgcc -lc |
# This accelerates instruction fetch after branches when C extension is enabled (irrelevant when C extension is disabled) |
CC_OPTS += -falign-functions=4 -falign-labels=4 -falign-loops=4 -falign-jumps=4 |
CC_OPTS += $(USER_FLAGS) |
|
|
# ----------------------------------------------------------------------------- |
# Application output definitions |
# ----------------------------------------------------------------------------- |
.PHONY: check info help elf_info clean clean_all bootloader |
.DEFAULT_GOAL := help |
|
# 'compile' is still here for compatibility |
exe: $(APP_ASM) $(APP_EXE) |
compile: $(APP_ASM) $(APP_EXE) |
install: $(APP_ASM) $(APP_IMG) |
all: $(APP_ASM) $(APP_EXE) $(APP_IMG) |
|
# Check if making bootloader |
# Use different base address and legth for instruction memory/"rom" (BOOTMEM instead of IMEM) |
# Also define "make_bootloader" for crt0.S |
target bootloader: CC_OPTS += -Wl,--defsym=make_bootloader=1 -Dmake_bootloader |
|
|
# ----------------------------------------------------------------------------- |
# Image generator targets |
# ----------------------------------------------------------------------------- |
# install/compile tools |
$(IMAGE_GEN): $(NEORV32_EXG_PATH)/image_gen.cpp |
@echo Compiling $(IMAGE_GEN) |
@$(CC_X86) $< -o $(IMAGE_GEN) |
|
|
# ----------------------------------------------------------------------------- |
# General targets: Assemble, compile, link, dump |
# ----------------------------------------------------------------------------- |
# Compile app *.s sources (assembly) |
%.s.o: %.s |
@$(CC) -c $(CC_OPTS) -I $(NEORV32_INC_PATH) $(ASM_INC) $< -o $@ |
|
# Compile app *.S sources (assembly + C pre-processor) |
%.S.o: %.S |
@$(CC) -c $(CC_OPTS) -I $(NEORV32_INC_PATH) $(ASM_INC) $< -o $@ |
|
# Compile app *.c sources |
%.c.o: %.c |
@$(CC) -c $(CC_OPTS) -I $(NEORV32_INC_PATH) $(APP_INC) $< -o $@ |
|
# Compile app *.cpp sources |
%.cpp.o: %.cpp |
@$(CC) -c $(CC_OPTS) -I $(NEORV32_INC_PATH) $(APP_INC) $< -o $@ |
|
# Link object files and show memory utilization |
main.elf: $(OBJ) |
@$(CC) $(CC_OPTS) -T $(LD_SCRIPT) $(OBJ) -o $@ -lm |
@echo "Memory utilization:" |
@$(SIZE) main.elf |
|
# Assembly listing file (for debugging) |
$(APP_ASM): main.elf |
@$(OBJDUMP) -d -S -z $< > $@ |
|
# Generate final executable from .text + .rodata + .data (in THIS order!) |
main.bin: main.elf $(APP_ASM) |
@$(OBJCOPY) -I elf32-little $< -j .text -O binary text.bin |
@$(OBJCOPY) -I elf32-little $< -j .rodata -O binary rodata.bin |
@$(OBJCOPY) -I elf32-little $< -j .data -O binary data.bin |
@cat text.bin rodata.bin data.bin > $@ |
@rm -f text.bin rodata.bin data.bin |
|
|
# ----------------------------------------------------------------------------- |
# Application targets: Generate binary executable, install (as VHDL file) |
# ----------------------------------------------------------------------------- |
# Generate NEORV32 executable image for upload via bootloader |
$(APP_EXE): main.bin $(IMAGE_GEN) |
@set -e |
@$(IMAGE_GEN) -app_bin $< $@ $(shell basename $(CURDIR)) |
@echo "Executable ($(APP_EXE)) size in bytes:" |
@wc -c < $(APP_EXE) |
|
# Generate NEORV32 executable VHDL boot image |
$(APP_IMG): main.bin $(IMAGE_GEN) |
@set -e |
@$(IMAGE_GEN) -app_img $< $@ $(shell basename $(CURDIR)) |
@echo "Installing application image to $(NEORV32_RTL_PATH)/$(APP_IMG)" |
@cp $(APP_IMG) $(NEORV32_RTL_PATH)/. |
|
|
# ----------------------------------------------------------------------------- |
# Bootloader targets |
# ----------------------------------------------------------------------------- |
# Create and install bootloader VHDL init image |
$(BOOT_IMG): main.bin $(IMAGE_GEN) |
@set -e |
@$(IMAGE_GEN) -bld_img $< $(BOOT_IMG) $(shell basename $(CURDIR)) |
@echo "Installing bootloader image to $(NEORV32_RTL_PATH)/$(BOOT_IMG)" |
@cp $(BOOT_IMG) $(NEORV32_RTL_PATH)/. |
|
# Just an alias that |
bootloader: $(BOOT_IMG) |
|
|
# ----------------------------------------------------------------------------- |
# Check toolchain |
# ----------------------------------------------------------------------------- |
check: $(IMAGE_GEN) |
@echo "---------------- Check: NEORV32_HOME folder ----------------" |
ifneq ($(shell [ -e $(NEORV32_HOME_MARKER) ] && echo 1 || echo 0 ), 1) |
$(error NEORV32_HOME folder not found!) |
endif |
@echo "NEORV32_HOME: $(NEORV32_HOME)" |
@echo "---------------- Check: $(CC) ----------------" |
@$(CC) -v |
@echo "---------------- Check: $(OBJDUMP) ----------------" |
@$(OBJDUMP) -V |
@echo "---------------- Check: $(OBJCOPY) ----------------" |
@$(OBJCOPY) -V |
@echo "---------------- Check: $(SIZE) ----------------" |
@$(SIZE) -V |
@echo "---------------- Check: NEORV32 image_gen ----------------" |
@$(IMAGE_GEN) -help |
@echo "---------------- Check: Native GCC ----------------" |
@$(CC_X86) -v |
@echo |
@echo "Toolchain check OK" |
|
|
# ----------------------------------------------------------------------------- |
# Upload executable via serial port to bootloader |
# ----------------------------------------------------------------------------- |
upload: $(APP_EXE) |
@sh $(NEORV32_EXG_PATH)/uart_upload.sh $(COM_PORT) $(APP_EXE) |
|
|
# ----------------------------------------------------------------------------- |
# Show configuration |
# ----------------------------------------------------------------------------- |
info: |
@echo "---------------- Info: Project ----------------" |
@echo "Project folder: $(shell basename $(CURDIR))" |
@echo "Source files: $(APP_SRC)" |
@echo "Include folder(s): $(APP_INC)" |
@echo "ASM include folder(s): $(ASM_INC)" |
@echo "---------------- Info: NEORV32 ----------------" |
@echo "NEORV32 home folder (NEORV32_HOME): $(NEORV32_HOME)" |
@echo "IMAGE_GEN: $(IMAGE_GEN)" |
@echo "Core source files:" |
@echo "$(CORE_SRC)" |
@echo "Core include folder:" |
@echo "$(NEORV32_INC_PATH)" |
@echo "---------------- Info: Objects ----------------" |
@echo "Project object files:" |
@echo "$(OBJ)" |
@echo "---------------- Info: RISC-V CPU ----------------" |
@echo "MARCH: $(MARCH)" |
@echo "MABI: $(MABI)" |
@echo "---------------- Info: Toolchain ----------------" |
@echo "Toolchain: $(RISCV_TOLLCHAIN)" |
@echo "CC: $(CC)" |
@echo "OBJDUMP: $(OBJDUMP)" |
@echo "OBJCOPY: $(OBJCOPY)" |
@echo "SIZE: $(SIZE)" |
@echo "---------------- Info: Compiler Libraries ----------------" |
@echo "LIBGCC:" |
@$(CC) -print-libgcc-file-name |
@echo "SEARCH-DIRS:" |
@$(CC) -print-search-dirs |
@echo "---------------- Info: Flags ----------------" |
@echo "USER_FLAGS: $(USER_FLAGS)" |
@echo "CC_OPTS: $(CC_OPTS)" |
@echo "---------------- Info: Host Native GCC Flags ----------------" |
@echo "CC_X86: $(CC_X86)" |
|
|
# ----------------------------------------------------------------------------- |
# Show final ELF details (just for debugging) |
# ----------------------------------------------------------------------------- |
elf_info: main.elf |
@$(OBJDUMP) -x main.elf |
|
|
# ----------------------------------------------------------------------------- |
# Help |
# ----------------------------------------------------------------------------- |
help: |
@echo "<<< NEORV32 Application Makefile >>>" |
@echo "Make sure to add the bin folder of RISC-V GCC to your PATH variable." |
@echo "Targets:" |
@echo " help - show this text" |
@echo " check - check toolchain" |
@echo " info - show makefile/toolchain configuration" |
@echo " exe - compile and generate <neorv32_exe.bin> executable for upload via bootloader" |
@echo " install - compile, generate and install VHDL IMEM boot image (for application)" |
@echo " all - compile and generate <neorv32_exe.bin> executable for upload via bootloader and generate and install VHDL IMEM boot image (for application)" |
@echo " clean - clean up project" |
@echo " clean_all - clean up project, core libraries and image generator" |
@echo " bootloader - compile, generate and install VHDL BOOTROM boot image (for bootloader only!)" |
@echo " upload - upload <neorv32_exe.bin> executable via serial port <COM_PORT> to bootloader" |
|
|
# ----------------------------------------------------------------------------- |
# Clean up |
# ----------------------------------------------------------------------------- |
clean: |
@rm -f *.elf *.o *.bin *.out *.asm *.vhd |
|
clean_all: clean |
@rm -f $(OBJ) $(IMAGE_GEN) |
/floating_point_test/neorv32_zfinx_extension_intrinsics.h
0,0 → 1,1396
// ################################################################################################# |
// # << NEORV32 - Intrinsics + Emulation Functions for the RISC-V "Zfinx" CPU extension >> # |
// # ********************************************************************************************* # |
// # The intrinsics provided by this library allow to use the hardware floating-point unit of the # |
// # RISC-V Zfinx CPU extension without the need for Zfinx support by the compiler / toolchain. # |
// # ********************************************************************************************* # |
// # BSD 3-Clause License # |
// # # |
// # Copyright (c) 2021, Stephan Nolting. All rights reserved. # |
// # # |
// # Redistribution and use in source and binary forms, with or without modification, are # |
// # permitted provided that the following conditions are met: # |
// # # |
// # 1. Redistributions of source code must retain the above copyright notice, this list of # |
// # conditions and the following disclaimer. # |
// # # |
// # 2. Redistributions in binary form must reproduce the above copyright notice, this list of # |
// # conditions and the following disclaimer in the documentation and/or other materials # |
// # provided with the distribution. # |
// # # |
// # 3. Neither the name of the copyright holder nor the names of its contributors may be used to # |
// # endorse or promote products derived from this software without specific prior written # |
// # permission. # |
// # # |
// # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS # |
// # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # |
// # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # |
// # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # |
// # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE # |
// # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED # |
// # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # |
// # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # |
// # OF THE POSSIBILITY OF SUCH DAMAGE. # |
// # ********************************************************************************************* # |
// # The NEORV32 Processor - https://github.com/stnolting/neorv32 (c) Stephan Nolting # |
// ################################################################################################# |
|
|
/**********************************************************************//** |
* @file floating_point_test/neorv32_zfinx_extension_intrinsics.h |
* @author Stephan Nolting |
* |
* @brief "Intrinsic" library for the NEORV32 single-precision floating-point in x registers (Zfinx) extension |
* @brief Also provides emulation functions for all intrinsics (functionality re-built in pure software). The functionality of the emulation |
* @brief functions is based on the RISC-V floating-point spec. |
* |
* @note All operations from this library use the default GCC "round to nearest, ties to even" rounding mode. |
* |
* @warning This library is just a temporary fall-back until the Zfinx extensions are supported by the upstream RISC-V GCC port. |
**************************************************************************/ |
|
#ifndef neorv32_zfinx_extension_intrinsics_h |
#define neorv32_zfinx_extension_intrinsics_h |
|
#define __USE_GNU |
|
#include <fenv.h> |
//#pragma STDC FENV_ACCESS ON |
|
#define _GNU_SOURCE |
|
#include <float.h> |
#include <math.h> |
|
|
/**********************************************************************//** |
* Sanity check |
**************************************************************************/ |
#if defined __riscv_f || (__riscv_flen == 32) |
#error Application programs using the Zfinx intrinsic library have to be compiled WITHOUT the <F> MARCH ISA attribute! |
#endif |
|
|
/**********************************************************************//** |
* Custom data type to access floating-point values as native floats and in binary representation |
**************************************************************************/ |
typedef union |
{ |
uint32_t binary_value; /**< Access as native float */ |
float float_value; /**< Access in binary representation */ |
} float_conv_t; |
|
|
// ################################################################################################ |
// Helper functions |
// ################################################################################################ |
|
/**********************************************************************//** |
* Flush to zero if denormal number. |
* |
* @warning Subnormal numbers are not supported yet! Flush them to zero. |
* |
* @param[in] tmp Source operand 1. |
* @return Result. |
**************************************************************************/ |
float subnormal_flush(float tmp) { |
|
float res = tmp; |
|
if (fpclassify(tmp) == FP_SUBNORMAL) { |
if (signbit(tmp) != 0) { |
res = -0.0f; |
} |
else { |
res = +0.0f; |
} |
} |
|
return res; |
} |
|
|
// ################################################################################################ |
// Exception access |
// ################################################################################################ |
|
/**********************************************************************//** |
* Get exception flags from fflags CSR (floating-point hardware). |
* |
* @return Floating point exception status word. |
**************************************************************************/ |
uint32_t get_hw_exceptions(void) { |
|
uint32_t res = neorv32_cpu_csr_read(CSR_FFLAGS); |
|
neorv32_cpu_csr_write(CSR_FFLAGS, 0); // clear status word |
|
return res; |
} |
|
|
/**********************************************************************//** |
* Get exception flags from C runtime (floating-point emulation). |
* |
* @warning WORK-IN-PROGRESS! |
* |
* @return Floating point exception status word. |
**************************************************************************/ |
uint32_t get_sw_exceptions(void) { |
|
const uint32_t FP_EXC_NV_C = 1 << 0; // invalid operation |
const uint32_t FP_EXC_DZ_C = 1 << 1; // divide by zero |
const uint32_t FP_EXC_OF_C = 1 << 2; // overflow |
const uint32_t FP_EXC_UF_C = 1 << 3; // underflow |
const uint32_t FP_EXC_NX_C = 1 << 4; // inexact |
|
int fpeRaised = fetestexcept(FE_ALL_EXCEPT); |
|
uint32_t res = 0; |
|
if (fpeRaised & FE_INVALID) { res |= FP_EXC_NV_C; } |
if (fpeRaised & FE_DIVBYZERO) { res |= FP_EXC_DZ_C; } |
if (fpeRaised & FE_OVERFLOW) { res |= FP_EXC_OF_C; } |
if (fpeRaised & FE_UNDERFLOW) { res |= FP_EXC_UF_C; } |
if (fpeRaised & FE_INEXACT) { res |= FP_EXC_NX_C; } |
|
feclearexcept(FE_ALL_EXCEPT); |
|
return res; |
} |
|
|
// ################################################################################################ |
// "Intrinsics" |
// ################################################################################################ |
|
/**********************************************************************//** |
* Single-precision floating-point addition |
* |
* @note "noinline" attributed to make sure arguments/return values are in a0 and a1. |
* |
* @param[in] rs1 Source operand 1 (a0). |
* @param[in] rs2 Source operand 2 (a1). |
* @return Result. |
**************************************************************************/ |
float __attribute__ ((noinline)) riscv_intrinsic_fadds(float rs1, float rs2) { |
|
float_conv_t opa, opb, res; |
opa.float_value = rs1; |
opb.float_value = rs2; |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = opa.binary_value; |
register uint32_t tmp_b __asm__ ("a1") = opb.binary_value; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); |
|
// fadd.s a0, a0, a1 |
CUSTOM_INSTR_R2_TYPE(0b0000000, a1, a0, 0b000, a0, 0b1010011); |
|
res.binary_value = result; |
return res.float_value; |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point subtraction |
* |
* @note "noinline" attributed to make sure arguments/return values are in a0 and a1. |
* |
* @param[in] rs1 Source operand 1 (a0). |
* @param[in] rs2 Source operand 2 (a1). |
* @return Result. |
**************************************************************************/ |
float __attribute__ ((noinline)) riscv_intrinsic_fsubs(float rs1, float rs2) { |
|
float_conv_t opa, opb, res; |
opa.float_value = rs1; |
opb.float_value = rs2; |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = opa.binary_value; |
register uint32_t tmp_b __asm__ ("a1") = opb.binary_value; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); |
|
// fsub.s a0, a0, a1 |
CUSTOM_INSTR_R2_TYPE(0b0000100, a1, a0, 0b000, a0, 0b1010011); |
|
res.binary_value = result; |
return res.float_value; |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point multiplication |
* |
* @note "noinline" attributed to make sure arguments/return values are in a0 and a1. |
* |
* @param[in] rs1 Source operand 1 (a0). |
* @param[in] rs2 Source operand 2 (a1). |
* @return Result. |
**************************************************************************/ |
float __attribute__ ((noinline)) riscv_intrinsic_fmuls(float rs1, float rs2) { |
|
float_conv_t opa, opb, res; |
opa.float_value = rs1; |
opb.float_value = rs2; |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = opa.binary_value; |
register uint32_t tmp_b __asm__ ("a1") = opb.binary_value; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); |
|
// fmul.s a0, a0, a1 |
CUSTOM_INSTR_R2_TYPE(0b0001000, a1, a0, 0b000, a0, 0b1010011); |
|
res.binary_value = result; |
return res.float_value; |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point minimum |
* |
* @note "noinline" attributed to make sure arguments/return values are in a0 and a1. |
* |
* @param[in] rs1 Source operand 1 (a0). |
* @param[in] rs2 Source operand 2 (a1). |
* @return Result. |
**************************************************************************/ |
float __attribute__ ((noinline)) riscv_intrinsic_fmins(float rs1, float rs2) { |
|
float_conv_t opa, opb, res; |
opa.float_value = rs1; |
opb.float_value = rs2; |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = opa.binary_value; |
register uint32_t tmp_b __asm__ ("a1") = opb.binary_value; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); |
|
// fmin.s a0, a0, a1 |
CUSTOM_INSTR_R2_TYPE(0b0010100, a1, a0, 0b000, a0, 0b1010011); |
|
res.binary_value = result; |
return res.float_value; |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point maximum |
* |
* @note "noinline" attributed to make sure arguments/return values are in a0 and a1. |
* |
* @param[in] rs1 Source operand 1 (a0). |
* @param[in] rs2 Source operand 2 (a1). |
* @return Result. |
**************************************************************************/ |
float __attribute__ ((noinline)) riscv_intrinsic_fmaxs(float rs1, float rs2) { |
|
float_conv_t opa, opb, res; |
opa.float_value = rs1; |
opb.float_value = rs2; |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = opa.binary_value; |
register uint32_t tmp_b __asm__ ("a1") = opb.binary_value; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); |
|
// fmax.s a0, a0, a1 |
CUSTOM_INSTR_R2_TYPE(0b0010100, a1, a0, 0b001, a0, 0b1010011); |
|
res.binary_value = result; |
return res.float_value; |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point convert float to unsigned integer |
* |
* @note "noinline" attributed to make sure arguments/return values are in a0 and a1. |
* |
* @param[in] rs1 Source operand 1 (a0). |
* @return Result. |
**************************************************************************/ |
uint32_t __attribute__ ((noinline)) riscv_intrinsic_fcvt_wus(float rs1) { |
|
float_conv_t opa; |
opa.float_value = rs1; |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = opa.binary_value; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], x0" : : [input_i] "r" (tmp_a)); |
|
// fcvt.wu.s a0, a0 |
CUSTOM_INSTR_R2_TYPE(0b1100000, x1, a0, 0b000, a0, 0b1010011); |
|
return result; |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point convert float to signed integer |
* |
* @note "noinline" attributed to make sure arguments/return values are in a0 and a1. |
* |
* @param[in] rs1 Source operand 1 (a0). |
* @return Result. |
**************************************************************************/ |
int32_t __attribute__ ((noinline)) riscv_intrinsic_fcvt_ws(float rs1) { |
|
float_conv_t opa; |
opa.float_value = rs1; |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = opa.binary_value; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], x0" : : [input_i] "r" (tmp_a)); |
|
// fcvt.w.s a0, a0 |
CUSTOM_INSTR_R2_TYPE(0b1100000, x0, a0, 0b000, a0, 0b1010011); |
|
return (int32_t)result; |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point convert unsigned integer to float |
* |
* @note "noinline" attributed to make sure arguments/return values are in a0 and a1. |
* |
* @param[in] rs1 Source operand 1 (a0). |
* @return Result. |
**************************************************************************/ |
float __attribute__ ((noinline)) riscv_intrinsic_fcvt_swu(uint32_t rs1) { |
|
float_conv_t res; |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = rs1; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], x0" : : [input_i] "r" (tmp_a)); |
|
// fcvt.s.wu a0, a0 |
CUSTOM_INSTR_R2_TYPE(0b1101000, x1, a0, 0b000, a0, 0b1010011); |
|
res.binary_value = result; |
return res.float_value; |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point convert signed integer to float |
* |
* @note "noinline" attributed to make sure arguments/return values are in a0 and a1. |
* |
* @param[in] rs1 Source operand 1 (a0). |
* @return Result. |
**************************************************************************/ |
float __attribute__ ((noinline)) riscv_intrinsic_fcvt_sw(int32_t rs1) { |
|
float_conv_t res; |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = (uint32_t)rs1; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], x0" : : [input_i] "r" (tmp_a)); |
|
// fcvt.s.w a0, a0 |
CUSTOM_INSTR_R2_TYPE(0b1101000, x0, a0, 0b000, a0, 0b1010011); |
|
res.binary_value = result; |
return res.float_value; |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point equal comparison |
* |
* @note "noinline" attributed to make sure arguments/return values are in a0 and a1. |
* |
* @param[in] rs1 Source operand 1 (a0). |
* @param[in] rs2 Source operand 2 (a1). |
* @return Result. |
**************************************************************************/ |
uint32_t __attribute__ ((noinline)) riscv_intrinsic_feqs(float rs1, float rs2) { |
|
float_conv_t opa, opb; |
opa.float_value = rs1; |
opb.float_value = rs2; |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = opa.binary_value; |
register uint32_t tmp_b __asm__ ("a1") = opb.binary_value; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); |
|
// feq.s a0, a0, a1 |
CUSTOM_INSTR_R2_TYPE(0b1010000, a1, a0, 0b010, a0, 0b1010011); |
|
return result; |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point less-than comparison |
* |
* @note "noinline" attributed to make sure arguments/return values are in a0 and a1. |
* |
* @param[in] rs1 Source operand 1 (a0). |
* @param[in] rs2 Source operand 2 (a1). |
* @return Result. |
**************************************************************************/ |
uint32_t __attribute__ ((noinline)) riscv_intrinsic_flts(float rs1, float rs2) { |
|
float_conv_t opa, opb; |
opa.float_value = rs1; |
opb.float_value = rs2; |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = opa.binary_value; |
register uint32_t tmp_b __asm__ ("a1") = opb.binary_value; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); |
|
// flt.s a0, a0, a1 |
CUSTOM_INSTR_R2_TYPE(0b1010000, a1, a0, 0b001, a0, 0b1010011); |
|
return result; |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point less-than-or-equal comparison |
* |
* @note "noinline" attributed to make sure arguments/return values are in a0 and a1. |
* |
* @param[in] rs1 Source operand 1 (a0). |
* @param[in] rs2 Source operand 2 (a1). |
* @return Result. |
**************************************************************************/ |
uint32_t __attribute__ ((noinline)) riscv_intrinsic_fles(float rs1, float rs2) { |
|
float_conv_t opa, opb; |
opa.float_value = rs1; |
opb.float_value = rs2; |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = opa.binary_value; |
register uint32_t tmp_b __asm__ ("a1") = opb.binary_value; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); |
|
// fle.s a0, a0, a1 |
CUSTOM_INSTR_R2_TYPE(0b1010000, a1, a0, 0b000, a0, 0b1010011); |
|
return result; |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point sign-injection |
* |
* @note "noinline" attributed to make sure arguments/return values are in a0 and a1. |
* |
* @param[in] rs1 Source operand 1 (a0). |
* @param[in] rs2 Source operand 2 (a1). |
* @return Result. |
**************************************************************************/ |
float __attribute__ ((noinline)) riscv_intrinsic_fsgnjs(float rs1, float rs2) { |
|
float_conv_t opa, opb, res; |
opa.float_value = rs1; |
opb.float_value = rs2; |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = opa.binary_value; |
register uint32_t tmp_b __asm__ ("a1") = opb.binary_value; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); |
|
// fsgnj.s a0, a0, a1 |
CUSTOM_INSTR_R2_TYPE(0b0010000, a1, a0, 0b000, a0, 0b1010011); |
|
res.binary_value = result; |
return res.float_value; |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point sign-injection NOT |
* |
* @note "noinline" attributed to make sure arguments/return values are in a0 and a1. |
* |
* @param[in] rs1 Source operand 1 (a0). |
* @param[in] rs2 Source operand 2 (a1). |
* @return Result. |
**************************************************************************/ |
float __attribute__ ((noinline)) riscv_intrinsic_fsgnjns(float rs1, float rs2) { |
|
float_conv_t opa, opb, res; |
opa.float_value = rs1; |
opb.float_value = rs2; |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = opa.binary_value; |
register uint32_t tmp_b __asm__ ("a1") = opb.binary_value; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); |
|
// fsgnjn.s a0, a0, a1 |
CUSTOM_INSTR_R2_TYPE(0b0010000, a1, a0, 0b001, a0, 0b1010011); |
|
res.binary_value = result; |
return res.float_value; |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point sign-injection XOR |
* |
* @note "noinline" attributed to make sure arguments/return values are in a0 and a1. |
* |
* @param[in] rs1 Source operand 1 (a0). |
* @param[in] rs2 Source operand 2 (a1). |
* @return Result. |
**************************************************************************/ |
float __attribute__ ((noinline)) riscv_intrinsic_fsgnjxs(float rs1, float rs2) { |
|
float_conv_t opa, opb, res; |
opa.float_value = rs1; |
opb.float_value = rs2; |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = opa.binary_value; |
register uint32_t tmp_b __asm__ ("a1") = opb.binary_value; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); |
|
// fsgnjx.s a0, a0, a1 |
CUSTOM_INSTR_R2_TYPE(0b0010000, a1, a0, 0b010, a0, 0b1010011); |
|
res.binary_value = result; |
return res.float_value; |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point number classification |
* |
* @note "noinline" attributed to make sure arguments/return values are in a0 and a1. |
* |
* @param[in] rs1 Source operand 1 (a0). |
* @return Result. |
**************************************************************************/ |
uint32_t __attribute__ ((noinline)) riscv_intrinsic_fclasss(float rs1) { |
|
float_conv_t opa; |
opa.float_value = rs1; |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = opa.binary_value; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], x0" : : [input_i] "r" (tmp_a)); |
|
// fclass.s a0, a0 |
CUSTOM_INSTR_R2_TYPE(0b1110000, x0, a0, 0b001, a0, 0b1010011); |
|
return result; |
} |
|
|
// ################################################################################################ |
// !!! UNSUPPORTED instructions !!! |
// ################################################################################################ |
|
/**********************************************************************//** |
* Single-precision floating-point division |
* |
* @note "noinline" attributed to make sure arguments/return values are in a0 and a1. |
* |
* @warning This instruction is not supported and should raise an illegal instruction exception when executed. |
* |
* @param[in] rs1 Source operand 1 (a0). |
* @param[in] rs2 Source operand 2 (a1). |
* @return Result. |
**************************************************************************/ |
float __attribute__ ((noinline)) riscv_intrinsic_fdivs(float rs1, float rs2) { |
|
float_conv_t opa, opb, res; |
opa.float_value = rs1; |
opb.float_value = rs2; |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = opa.binary_value; |
register uint32_t tmp_b __asm__ ("a1") = opb.binary_value; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); |
|
// fdiv.s a0, a0, x1 |
CUSTOM_INSTR_R2_TYPE(0b0001100, a1, a0, 0b000, a0, 0b1010011); |
|
res.binary_value = result; |
return res.float_value; |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point square root |
* |
* @note "noinline" attributed to make sure arguments/return values are in a0 and a1. |
* |
* @warning This instruction is not supported and should raise an illegal instruction exception when executed. |
* |
* @param[in] rs1 Source operand 1 (a0). |
* @return Result. |
**************************************************************************/ |
float __attribute__ ((noinline)) riscv_intrinsic_fsqrts(float rs1) { |
|
float_conv_t opa, res; |
opa.float_value = rs1; |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = opa.binary_value; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], x0" : : [input_i] "r" (tmp_a)); |
|
// fsqrt.s a0, a0, a1 |
CUSTOM_INSTR_R2_TYPE(0b0101100, a1, a0, 0b000, a0, 0b1010011); |
|
res.binary_value = result; |
return res.float_value; |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point fused multiply-add |
* |
* @note "noinline" attributed to make sure arguments/return values are in a0, a1 and a2. |
* |
* @warning This instruction is not supported and should raise an illegal instruction exception when executed. |
* |
* @param[in] rs1 Source operand 1 (a0) |
* @param[in] rs2 Source operand 2 (a1) |
* @param[in] rs3 Source operand 3 (a2) |
* @return Result. |
**************************************************************************/ |
float __attribute__ ((noinline)) riscv_intrinsic_fmadds(float rs1, float rs2, float rs3) { |
|
float_conv_t opa, opb, opc, res; |
opa.float_value = rs1; |
opb.float_value = rs2; |
opc.float_value = rs3; |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = opa.binary_value; |
register uint32_t tmp_b __asm__ ("a1") = opb.binary_value; |
register uint32_t tmp_c __asm__ ("a2") = opc.binary_value; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); |
asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_b), [input_j] "r" (tmp_c)); |
|
// fmadd.s a0, a0, a1, a2 |
CUSTOM_INSTR_R3_TYPE(a2, a1, a0, 0b000, a0, 0b1000011); |
|
res.binary_value = result; |
return res.float_value; |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point fused multiply-sub |
* |
* @note "noinline" attributed to make sure arguments/return values are in a0, a1 and a2. |
* |
* @warning This instruction is not supported and should raise an illegal instruction exception when executed. |
* |
* @param[in] rs1 Source operand 1 (a0) |
* @param[in] rs2 Source operand 2 (a1) |
* @param[in] rs3 Source operand 3 (a2) |
* @return Result. |
**************************************************************************/ |
float __attribute__ ((noinline)) riscv_intrinsic_fmsubs(float rs1, float rs2, float rs3) { |
|
float_conv_t opa, opb, opc, res; |
opa.float_value = rs1; |
opb.float_value = rs2; |
opc.float_value = rs3; |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = opa.binary_value; |
register uint32_t tmp_b __asm__ ("a1") = opb.binary_value; |
register uint32_t tmp_c __asm__ ("a2") = opc.binary_value; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); |
asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_b), [input_j] "r" (tmp_c)); |
|
// fmsub.s a0, a0, a1, a2 |
CUSTOM_INSTR_R3_TYPE(a2, a1, a0, 0b000, a0, 0b1000111); |
|
res.binary_value = result; |
return res.float_value; |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point fused negated multiply-sub |
* |
* @note "noinline" attributed to make sure arguments/return values are in a0, a1 and a2. |
* |
* @warning This instruction is not supported and should raise an illegal instruction exception when executed. |
* |
* @param[in] rs1 Source operand 1 (a0) |
* @param[in] rs2 Source operand 2 (a1) |
* @param[in] rs3 Source operand 3 (a2) |
* @return Result. |
**************************************************************************/ |
float __attribute__ ((noinline)) riscv_intrinsic_fnmsubs(float rs1, float rs2, float rs3) { |
|
float_conv_t opa, opb, opc, res; |
opa.float_value = rs1; |
opb.float_value = rs2; |
opc.float_value = rs3; |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = opa.binary_value; |
register uint32_t tmp_b __asm__ ("a1") = opb.binary_value; |
register uint32_t tmp_c __asm__ ("a2") = opc.binary_value; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); |
asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_b), [input_j] "r" (tmp_c)); |
|
// fnmsub.s a0, a0, a1, a2 |
CUSTOM_INSTR_R3_TYPE(a2, a1, a0, 0b000, a0, 0b1001011); |
|
res.binary_value = result; |
return res.float_value; |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point fused negated multiply-add |
* |
* @note "noinline" attributed to make sure arguments/return values are in a0, a1 and a2. |
* |
* @warning This instruction is not supported and should raise an illegal instruction exception when executed. |
* |
* @param[in] rs1 Source operand 1 (a0) |
* @param[in] rs2 Source operand 2 (a1) |
* @param[in] rs3 Source operand 3 (a2) |
* @return Result. |
**************************************************************************/ |
float __attribute__ ((noinline)) riscv_intrinsic_fnmadds(float rs1, float rs2, float rs3) { |
|
float_conv_t opa, opb, opc, res; |
opa.float_value = rs1; |
opb.float_value = rs2; |
opc.float_value = rs3; |
|
register uint32_t result __asm__ ("a0"); |
register uint32_t tmp_a __asm__ ("a0") = opa.binary_value; |
register uint32_t tmp_b __asm__ ("a1") = opb.binary_value; |
register uint32_t tmp_c __asm__ ("a2") = opc.binary_value; |
|
// dummy instruction to prevent GCC "constprop" optimization |
asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); |
asm volatile ("add x0, %[input_i], %[input_j]" : : [input_i] "r" (tmp_b), [input_j] "r" (tmp_c)); |
|
// fnmadd.s a0, a0, a1, a2 |
CUSTOM_INSTR_R3_TYPE(a2, a1, a0, 0b000, a0, 0b1001111); |
|
res.binary_value = result; |
return res.float_value; |
} |
|
|
// ################################################################################################ |
// Emulation functions |
// ################################################################################################ |
|
/**********************************************************************//** |
* Single-precision floating-point addition |
* |
* @param[in] rs1 Source operand 1. |
* @param[in] rs2 Source operand 2. |
* @return Result. |
**************************************************************************/ |
float riscv_emulate_fadds(float rs1, float rs2) { |
|
float opa = subnormal_flush(rs1); |
float opb = subnormal_flush(rs2); |
|
float res = opa + opb; |
return subnormal_flush(res); |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point subtraction |
* |
* @param[in] rs1 Source operand 1. |
* @param[in] rs2 Source operand 2. |
* @return Result. |
**************************************************************************/ |
float riscv_emulate_fsubs(float rs1, float rs2) { |
|
float opa = subnormal_flush(rs1); |
float opb = subnormal_flush(rs2); |
|
float res = opa - opb; |
return subnormal_flush(res); |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point multiplication |
* |
* @param[in] rs1 Source operand 1. |
* @param[in] rs2 Source operand 2. |
* @return Result. |
**************************************************************************/ |
float riscv_emulate_fmuls(float rs1, float rs2) { |
|
float opa = subnormal_flush(rs1); |
float opb = subnormal_flush(rs2); |
|
float res = opa * opb; |
return subnormal_flush(res); |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point minimum |
* |
* @param[in] rs1 Source operand 1. |
* @param[in] rs2 Source operand 2. |
* @return Result. |
**************************************************************************/ |
float riscv_emulate_fmins(float rs1, float rs2) { |
|
float opa = subnormal_flush(rs1); |
float opb = subnormal_flush(rs2); |
|
union { |
uint32_t binary_value; /**< Access as native float */ |
float float_value; /**< Access in binary representation */ |
} tmp_a, tmp_b; |
|
if ((fpclassify(opa) == FP_NAN) && (fpclassify(opb) == FP_NAN)) { |
return nanf(""); |
} |
|
if (fpclassify(opa) == FP_NAN) { |
return opb; |
} |
|
if (fpclassify(opb) == FP_NAN) { |
return opa; |
} |
|
// RISC-V spec: -0 < +0 |
tmp_a.float_value = opa; |
tmp_b.float_value = opb; |
if (((tmp_a.binary_value == 0x80000000) && (tmp_b.binary_value == 0x00000000)) || |
((tmp_a.binary_value == 0x00000000) && (tmp_b.binary_value == 0x80000000))) { |
return -0.0f; |
} |
|
return fmin(opa, opb); |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point maximum |
* |
* @param[in] rs1 Source operand 1. |
* @param[in] rs2 Source operand 2. |
* @return Result. |
**************************************************************************/ |
float riscv_emulate_fmaxs(float rs1, float rs2) { |
|
float opa = subnormal_flush(rs1); |
float opb = subnormal_flush(rs2); |
|
union { |
uint32_t binary_value; /**< Access as native float */ |
float float_value; /**< Access in binary representation */ |
} tmp_a, tmp_b; |
|
|
if ((fpclassify(opa) == FP_NAN) && (fpclassify(opb) == FP_NAN)) { |
return nanf(""); |
} |
|
if (fpclassify(opa) == FP_NAN) { |
return opb; |
} |
|
if (fpclassify(opb) == FP_NAN) { |
return opa; |
} |
|
// RISC-V spec: -0 < +0 |
tmp_a.float_value = opa; |
tmp_b.float_value = opb; |
if (((tmp_a.binary_value == 0x80000000) && (tmp_b.binary_value == 0x00000000)) || |
((tmp_a.binary_value == 0x00000000) && (tmp_b.binary_value == 0x80000000))) { |
return +0.0f; |
} |
|
return fmax(opa, opb); |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point float to unsigned integer |
* |
* @param[in] rs1 Source operand 1. |
* @return Result. |
**************************************************************************/ |
uint32_t riscv_emulate_fcvt_wus(float rs1) { |
|
float opa = subnormal_flush(rs1); |
|
return (uint32_t)roundf(opa); |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point float to signed integer |
* |
* @param[in] rs1 Source operand 1. |
* @return Result. |
**************************************************************************/ |
int32_t riscv_emulate_fcvt_ws(float rs1) { |
|
float opa = subnormal_flush(rs1); |
|
return (int32_t)roundf(opa); |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point unsigned integer to float |
* |
* @param[in] rs1 Source operand 1. |
* @return Result. |
**************************************************************************/ |
float riscv_emulate_fcvt_swu(uint32_t rs1) { |
|
return (float)rs1; |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point signed integer to float |
* |
* @param[in] rs1 Source operand 1. |
* @return Result. |
**************************************************************************/ |
float riscv_emulate_fcvt_sw(int32_t rs1) { |
|
return (float)rs1; |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point equal comparison |
* |
* @param[in] rs1 Source operand 1. |
* @param[in] rs2 Source operand 2. |
* @return Result. |
**************************************************************************/ |
uint32_t riscv_emulate_feqs(float rs1, float rs2) { |
|
float opa = subnormal_flush(rs1); |
float opb = subnormal_flush(rs2); |
|
if ((fpclassify(opa) == FP_NAN) || (fpclassify(opb) == FP_NAN)) { |
return 0; |
} |
|
if isless(opa, opb) { |
return 0; |
} |
else if isgreater(opa, opb) { |
return 0; |
} |
else { |
return 1; |
} |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point less-than comparison |
* |
* @param[in] rs1 Source operand 1. |
* @param[in] rs2 Source operand 2. |
* @return Result. |
**************************************************************************/ |
uint32_t riscv_emulate_flts(float rs1, float rs2) { |
|
float opa = subnormal_flush(rs1); |
float opb = subnormal_flush(rs2); |
|
if ((fpclassify(opa) == FP_NAN) || (fpclassify(opb) == FP_NAN)) { |
return 0; |
} |
|
if isless(opa, opb) { |
return 1; |
} |
else { |
return 0; |
} |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point less-than-or-equal comparison |
* |
* @param[in] rs1 Source operand 1. |
* @param[in] rs2 Source operand 2. |
* @return Result. |
**************************************************************************/ |
uint32_t riscv_emulate_fles(float rs1, float rs2) { |
|
float opa = subnormal_flush(rs1); |
float opb = subnormal_flush(rs2); |
|
if ((fpclassify(opa) == FP_NAN) || (fpclassify(opb) == FP_NAN)) { |
return 0; |
} |
|
if islessequal(opa, opb) { |
return 1; |
} |
else { |
return 0; |
} |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point sign-injection |
* |
* @param[in] rs1 Source operand 1. |
* @param[in] rs2 Source operand 2. |
* @return Result. |
**************************************************************************/ |
float riscv_emulate_fsgnjs(float rs1, float rs2) { |
|
float opa = subnormal_flush(rs1); |
float opb = subnormal_flush(rs2); |
|
int sign_1 = (int)signbit(opa); |
int sign_2 = (int)signbit(opb); |
float res = 0; |
|
if (sign_2 != 0) { // opb is negative |
if (sign_1 == 0) { |
res = -opa; |
} |
else { |
res = opa; |
} |
} |
else { // opb is positive |
if (sign_1 == 0) { |
res = opa; |
} |
else { |
res = -opa; |
} |
} |
|
return res; |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point sign-injection NOT |
* |
* @param[in] rs1 Source operand 1. |
* @param[in] rs2 Source operand 2. |
* @return Result. |
**************************************************************************/ |
float riscv_emulate_fsgnjns(float rs1, float rs2) { |
|
float opa = subnormal_flush(rs1); |
float opb = subnormal_flush(rs2); |
|
int sign_1 = (int)signbit(opa); |
int sign_2 = (int)signbit(opb); |
float res = 0; |
|
if (sign_2 != 0) { // opb is negative |
if (sign_1 == 0) { |
res = opa; |
} |
else { |
res = -opa; |
} |
} |
else { // opb is positive |
if (sign_1 == 0) { |
res = -opa; |
} |
else { |
res = opa; |
} |
} |
|
return res; |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point sign-injection XOR |
* |
* @param[in] rs1 Source operand 1. |
* @param[in] rs2 Source operand 2. |
* @return Result. |
**************************************************************************/ |
float riscv_emulate_fsgnjxs(float rs1, float rs2) { |
|
float opa = subnormal_flush(rs1); |
float opb = subnormal_flush(rs2); |
|
int sign_1 = (int)signbit(opa); |
int sign_2 = (int)signbit(opb); |
float res = 0; |
|
if (((sign_1 == 0) && (sign_2 != 0)) || ((sign_1 != 0) && (sign_2 == 0))) { |
if (sign_1 == 0) { |
res = -opa; |
} |
else { |
res = opa; |
} |
} |
else { |
if (sign_1 == 0) { |
res = opa; |
} |
else { |
res = -opa; |
} |
} |
|
return res; |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point number classification |
* |
* @param[in] rs1 Source operand 1. |
* @return Result. |
**************************************************************************/ |
uint32_t riscv_emulate_fclasss(float rs1) { |
|
float opa = subnormal_flush(rs1); |
|
union { |
uint32_t binary_value; /**< Access as native float */ |
float float_value; /**< Access in binary representation */ |
} aux; |
|
// RISC-V classify result layout |
const uint32_t CLASS_NEG_INF = 1 << 0; // negative infinity |
const uint32_t CLASS_NEG_NORM = 1 << 1; // negative normal number |
const uint32_t CLASS_NEG_DENORM = 1 << 2; // negative subnormal number |
const uint32_t CLASS_NEG_ZERO = 1 << 3; // negative zero |
const uint32_t CLASS_POS_ZERO = 1 << 4; // positive zero |
const uint32_t CLASS_POS_DENORM = 1 << 5; // positive subnormal number |
const uint32_t CLASS_POS_NORM = 1 << 6; // positive normal number |
const uint32_t CLASS_POS_INF = 1 << 7; // positive infinity |
const uint32_t CLASS_SNAN = 1 << 8; // signaling NaN (sNaN) |
const uint32_t CLASS_QNAN = 1 << 9; // quiet NaN (qNaN) |
|
int tmp = fpclassify(opa); |
int sgn = (int)signbit(opa); |
|
uint32_t res = 0; |
|
// infinity |
if (tmp == FP_INFINITE) { |
if (sgn) { res |= CLASS_NEG_INF; } |
else { res |= CLASS_POS_INF; } |
} |
|
// zero |
if (tmp == FP_ZERO) { |
if (sgn) { res |= CLASS_NEG_ZERO; } |
else { res |= CLASS_POS_ZERO; } |
} |
|
// normal |
if (tmp == FP_NORMAL) { |
if (sgn) { res |= CLASS_NEG_NORM; } |
else { res |= CLASS_POS_NORM; } |
} |
|
// subnormal |
if (tmp == FP_SUBNORMAL) { |
if (sgn) { res |= CLASS_NEG_DENORM; } |
else { res |= CLASS_POS_DENORM; } |
} |
|
// NaN |
if (tmp == FP_NAN) { |
aux.float_value = opa; |
if ((aux.binary_value >> 22) & 0b1) { // bit 22 (mantissa's MSB) is set -> canonical (quiet) NAN |
res |= CLASS_QNAN; |
} |
else { |
res |= CLASS_SNAN; |
} |
} |
|
return res; |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point division |
* |
* @param[in] rs1 Source operand 1. |
* @param[in] rs2 Source operand 2. |
* @return Result. |
**************************************************************************/ |
float riscv_emulate_fdivs(float rs1, float rs2) { |
|
float opa = subnormal_flush(rs1); |
float opb = subnormal_flush(rs2); |
|
float res = opa / opb; |
return subnormal_flush(res); |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point square root |
* |
* @param[in] rs1 Source operand 1. |
* @return Result. |
**************************************************************************/ |
float riscv_emulate_fsqrts(float rs1) { |
|
float opa = subnormal_flush(rs1); |
|
float res = sqrtf(opa); |
return subnormal_flush(res); |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point fused multiply-add |
* |
* @note "noinline" attributed to make sure arguments/return values are in a0 and a1. |
* |
* @warning This instruction is not supported! |
* |
* @param[in] rs1 Source operand 1 |
* @param[in] rs2 Source operand 2 |
* @param[in] rs3 Source operand 3 |
* @return Result. |
**************************************************************************/ |
float riscv_emulate_fmadds(float rs1, float rs2, float rs3) { |
|
float opa = subnormal_flush(rs1); |
float opb = subnormal_flush(rs2); |
float opc = subnormal_flush(rs3); |
|
float res = (opa * opb) + opc; |
return subnormal_flush(res); |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point fused multiply-sub |
* |
* @param[in] rs1 Source operand 1 |
* @param[in] rs2 Source operand 2 |
* @param[in] rs3 Source operand 3 |
* @return Result. |
**************************************************************************/ |
float riscv_emulate_fmsubs(float rs1, float rs2, float rs3) { |
|
float opa = subnormal_flush(rs1); |
float opb = subnormal_flush(rs2); |
float opc = subnormal_flush(rs3); |
|
float res = (opa * opb) - opc; |
return subnormal_flush(res); |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point fused negated multiply-sub |
* |
* @param[in] rs1 Source operand 1 |
* @param[in] rs2 Source operand 2 |
* @param[in] rs3 Source operand 3 |
* @return Result. |
**************************************************************************/ |
float riscv_emulate_fnmsubs(float rs1, float rs2, float rs3) { |
|
float opa = subnormal_flush(rs1); |
float opb = subnormal_flush(rs2); |
float opc = subnormal_flush(rs3); |
|
float res = -(opa * opb) + opc; |
return subnormal_flush(res); |
} |
|
|
/**********************************************************************//** |
* Single-precision floating-point fused negated multiply-add |
* |
* @param[in] rs1 Source operand 1 |
* @param[in] rs2 Source operand 2 |
* @param[in] rs3 Source operand 3 |
* @return Result. |
**************************************************************************/ |
float riscv_emulate_fnmadds(float rs1, float rs2, float rs3) { |
|
float opa = subnormal_flush(rs1); |
float opb = subnormal_flush(rs2); |
float opc = subnormal_flush(rs3); |
|
float res = -(opa * opb) - opc; |
return subnormal_flush(res); |
} |
|
|
#endif // neorv32_zfinx_extension_intrinsics_h |
|
/game_of_life/makefile
1,11 → 1,11
################################################################################################# |
# << NEORV32 - Application Makefile >> # |
# ********************************************************************************************* # |
# Make sure to add the riscv GCC compiler's bin folder to your PATH environment variable. # |
# Make sure to add the RISC-V GCC compiler's bin folder to your PATH environment variable. # |
# ********************************************************************************************* # |
# BSD 3-Clause License # |
# # |
# Copyright (c) 2020, Stephan Nolting. All rights reserved. # |
# Copyright (c) 2021, Stephan Nolting. All rights reserved. # |
# # |
# Redistribution and use in source and binary forms, with or without modification, are # |
# permitted provided that the following conditions are met: # |
126,7 → 126,7
IMAGE_GEN = $(NEORV32_EXG_PATH)/image_gen |
|
# Compiler & linker flags |
CC_OPTS = $(MARCH) $(MABI) $(EFFORT) -Wall -ffunction-sections -fdata-sections -nostartfiles |
CC_OPTS = $(MARCH) $(MABI) $(EFFORT) -Wall -ffunction-sections -fdata-sections -nostartfiles -mno-fdiv |
CC_OPTS += -Wl,--gc-sections -lm -lc -lgcc -lc |
# This accelerates instruction fetch after branches when C extension is enabled (irrelevant when C extension is disabled) |
CC_OPTS += -falign-functions=4 -falign-labels=4 -falign-loops=4 -falign-jumps=4 |
/hello_world/makefile
1,11 → 1,11
################################################################################################# |
# << NEORV32 - Application Makefile >> # |
# ********************************************************************************************* # |
# Make sure to add the riscv GCC compiler's bin folder to your PATH environment variable. # |
# Make sure to add the RISC-V GCC compiler's bin folder to your PATH environment variable. # |
# ********************************************************************************************* # |
# BSD 3-Clause License # |
# # |
# Copyright (c) 2020, Stephan Nolting. All rights reserved. # |
# Copyright (c) 2021, Stephan Nolting. All rights reserved. # |
# # |
# Redistribution and use in source and binary forms, with or without modification, are # |
# permitted provided that the following conditions are met: # |
126,7 → 126,7
IMAGE_GEN = $(NEORV32_EXG_PATH)/image_gen |
|
# Compiler & linker flags |
CC_OPTS = $(MARCH) $(MABI) $(EFFORT) -Wall -ffunction-sections -fdata-sections -nostartfiles |
CC_OPTS = $(MARCH) $(MABI) $(EFFORT) -Wall -ffunction-sections -fdata-sections -nostartfiles -mno-fdiv |
CC_OPTS += -Wl,--gc-sections -lm -lc -lgcc -lc |
# This accelerates instruction fetch after branches when C extension is enabled (irrelevant when C extension is disabled) |
CC_OPTS += -falign-functions=4 -falign-labels=4 -falign-loops=4 -falign-jumps=4 |
/hex_viewer/makefile
1,11 → 1,11
################################################################################################# |
# << NEORV32 - Application Makefile >> # |
# ********************************************************************************************* # |
# Make sure to add the riscv GCC compiler's bin folder to your PATH environment variable. # |
# Make sure to add the RISC-V GCC compiler's bin folder to your PATH environment variable. # |
# ********************************************************************************************* # |
# BSD 3-Clause License # |
# # |
# Copyright (c) 2020, Stephan Nolting. All rights reserved. # |
# Copyright (c) 2021, Stephan Nolting. All rights reserved. # |
# # |
# Redistribution and use in source and binary forms, with or without modification, are # |
# permitted provided that the following conditions are met: # |
126,7 → 126,7
IMAGE_GEN = $(NEORV32_EXG_PATH)/image_gen |
|
# Compiler & linker flags |
CC_OPTS = $(MARCH) $(MABI) $(EFFORT) -Wall -ffunction-sections -fdata-sections -nostartfiles |
CC_OPTS = $(MARCH) $(MABI) $(EFFORT) -Wall -ffunction-sections -fdata-sections -nostartfiles -mno-fdiv |
CC_OPTS += -Wl,--gc-sections -lm -lc -lgcc -lc |
# This accelerates instruction fetch after branches when C extension is enabled (irrelevant when C extension is disabled) |
CC_OPTS += -falign-functions=4 -falign-labels=4 -falign-loops=4 -falign-jumps=4 |