OpenCores
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

powered by: WebSVN 2.1.0

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