Initial commit
This commit is contained in:
		
							
								
								
									
										13
									
								
								Libs/RiscV/NEORV32/sw/example/bitmanip_test/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								Libs/RiscV/NEORV32/sw/example/bitmanip_test/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| # NEORV32 Bit-Manipulation `B` Extension | ||||
|  | ||||
| :warning: The RISC-V bit-manipulation extension is frozen but not yet officially ratified. | ||||
|  | ||||
| :warning: The NEORV32 bit manipulation extensions `B` only supports the `Zbb` and `Zba` sub-extension | ||||
| (basic bit-manipulation operation) yet. | ||||
|  | ||||
| The provided test program `main.c` verifies all currently implemented instruction by checking the results against a pure-software emulation model. | ||||
| The emulation functions as well as the available **intrinsics** for the sub-extension are located in `neorv32_b_extension_intrinsics.h`. | ||||
|  | ||||
| :information_source: More information regarding the RISC-V bit manipulation extension can be found in the officail GitHub repo: | ||||
| [github.com/riscv/riscv-bitmanip](https://github.com/riscv/riscv-bitmanip). | ||||
| The specification of the bit-manipulation spec supported by the NEORV32 can be found in `docs/references/bitmanip-draft.pdf`. | ||||
							
								
								
									
										40
									
								
								Libs/RiscV/NEORV32/sw/example/bitmanip_test/makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								Libs/RiscV/NEORV32/sw/example/bitmanip_test/makefile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | ||||
| ################################################################################################# | ||||
| # << 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 # | ||||
| ################################################################################################# | ||||
|  | ||||
| # Modify this variable to fit your NEORV32 setup (neorv32 home folder) | ||||
| NEORV32_HOME ?= ../../.. | ||||
|  | ||||
| include $(NEORV32_HOME)/sw/common/common.mk | ||||
| @@ -0,0 +1,903 @@ | ||||
| // ################################################################################################# | ||||
| // # << NEORV32 - Intrinsics + Emulation Functions for the CPU B extension >>                      # | ||||
| // # ********************************************************************************************* # | ||||
| // # 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 support by the compiler.                      # | ||||
| // # ********************************************************************************************* # | ||||
| // # 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 bitmanip_test/neorv32_b_extension_intrinsics.h | ||||
|  * @author Stephan Nolting | ||||
|  * @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 extension is supported by the upstream RISC-V GCC port. | ||||
|  **************************************************************************/ | ||||
|   | ||||
| #ifndef neorv32_b_extension_intrinsics_h | ||||
| #define neorv32_b_extension_intrinsics_h | ||||
|  | ||||
|  | ||||
| // ################################################################################################ | ||||
| // "Intrinsics" | ||||
| // ################################################################################################ | ||||
|  | ||||
|  | ||||
| // ================================================================================================ | ||||
| // Zbb - Base instructions | ||||
| // ================================================================================================ | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Bit manipulation CLZ (count leading zeros) [B.Zbb] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @return Number of leading zeros in source operand. | ||||
|  **************************************************************************/ | ||||
| inline uint32_t __attribute__ ((always_inline)) 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 ("" : [output] "=r" (result) : [input_i] "r" (tmp_a)); | ||||
|  | ||||
|   // clz a0, a0 | ||||
|   CUSTOM_INSTR_R1_TYPE(0b0110000, 0b00000, a0, 0b001, a0, 0b0010011); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Bit manipulation CTZ (count trailing zeros) [B.Zbb] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @return Number of trailing zeros in source operand. | ||||
|  **************************************************************************/ | ||||
| inline uint32_t __attribute__ ((always_inline)) 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 ("" : [output] "=r" (result) : [input_i] "r" (tmp_a)); | ||||
|  | ||||
|   // ctz a0, a0 | ||||
|   CUSTOM_INSTR_R1_TYPE(0b0110000, 0b00001, a0, 0b001, a0, 0b0010011); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Bit manipulation CPOP (count set bits) [B.Zbb] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @return Number of set bits in source operand. | ||||
|  **************************************************************************/ | ||||
| inline uint32_t __attribute__ ((always_inline)) 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 ("" : [output] "=r" (result) : [input_i] "r" (tmp_a)); | ||||
|  | ||||
|   // cpop a0, a0 | ||||
|   CUSTOM_INSTR_R1_TYPE(0b0110000, 0b00010, a0, 0b001, a0, 0b0010011); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Bit manipulation SEXT.B (sign-extend byte) [B.Zbb] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @return Sign extended byte (operand(7:0)). | ||||
|  **************************************************************************/ | ||||
| inline uint32_t __attribute__ ((always_inline)) 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 ("" : [output] "=r" (result) : [input_i] "r" (tmp_a)); | ||||
|  | ||||
|   // sext.b a0, a0 | ||||
|   CUSTOM_INSTR_R1_TYPE(0b0110000, 0b00100, a0, 0b001, a0, 0b0010011); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Bit manipulation SEXT.H (sign-extend half-word) [B.Zbb] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @return Sign-extended half-word (operand(15:0)). | ||||
|  **************************************************************************/ | ||||
| inline uint32_t __attribute__ ((always_inline)) 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 ("" : [output] "=r" (result) : [input_i] "r" (tmp_a)); | ||||
|  | ||||
|   // sext.h a0, a0 | ||||
|   CUSTOM_INSTR_R1_TYPE(0b0110000, 0b00101, a0, 0b001, a0, 0b0010011); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Bit manipulation ZEXT.H (zero-extend half-word) [B.Zbb] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @return Zero-extended half-word (operand(15:0)). | ||||
|  **************************************************************************/ | ||||
| inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_zexth(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 ("" : [output] "=r" (result) : [input_i] "r" (tmp_a)); | ||||
|  | ||||
|   // sext.h a0, a0 | ||||
|   CUSTOM_INSTR_R1_TYPE(0b0000100, 0b00000, a0, 0b100, a0, 0b0110011); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Bit manipulation MIN (select signed minimum) [B.Zbb] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @param[in] rs2 Source operand 2 (a0). | ||||
|  * @return Signed minimum. | ||||
|  **************************************************************************/ | ||||
| inline uint32_t __attribute__ ((always_inline)) 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 ("" : [output] "=r" (result) : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); | ||||
|  | ||||
|   // min a0, a0, a1 | ||||
|   CUSTOM_INSTR_R2_TYPE(0b0000101, a1, a0, 0b100, a0, 0b0110011); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Bit manipulation MINU (select unsigned minimum) [B.Zbb] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @param[in] rs2 Source operand 2 (a0). | ||||
|  * @return Unsigned minimum. | ||||
|  **************************************************************************/ | ||||
| inline uint32_t __attribute__ ((always_inline)) 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 ("" : [output] "=r" (result) : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); | ||||
|  | ||||
|   // minu a0, a0, a1 | ||||
|   CUSTOM_INSTR_R2_TYPE(0b0000101, a1, a0, 0b101, a0, 0b0110011); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Bit manipulation MAX (select signed maximum) [B.Zbb] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @param[in] rs2 Source operand 2 (a0). | ||||
|  * @return Signed maximum. | ||||
|  **************************************************************************/ | ||||
| inline uint32_t __attribute__ ((always_inline)) 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 ("" : [output] "=r" (result) : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); | ||||
|  | ||||
|   // max a0, a0, a1 | ||||
|   CUSTOM_INSTR_R2_TYPE(0b0000101, a1, a0, 0b110, a0, 0b0110011); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Bit manipulation MAXU (select unsigned maximum) [B.Zbb] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @param[in] rs2 Source operand 2 (a0). | ||||
|  * @return Unsigned maximum. | ||||
|  **************************************************************************/ | ||||
| inline uint32_t __attribute__ ((always_inline)) 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 ("" : [output] "=r" (result) : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); | ||||
|  | ||||
|   // maxu a0, a0, a1 | ||||
|   CUSTOM_INSTR_R2_TYPE(0b0000101, a1, a0, 0b111, a0, 0b0110011); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Bit manipulation ANDN (logical and-negate) [B.Zbb] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @param[in] rs2 Source operand 2 (a0). | ||||
|  * @return Operand 1 AND NOT operand 2. | ||||
|  **************************************************************************/ | ||||
| inline inline uint32_t __attribute__ ((always_inline)) 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 ("" : [output] "=r" (result) : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); | ||||
|  | ||||
|   // andn a0, a0, a1 | ||||
|   CUSTOM_INSTR_R2_TYPE(0b0100000, a1, a0, 0b111, a0, 0b0110011); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Bit manipulation ORN (logical or-negate) [B.Zbb] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @param[in] rs2 Source operand 2 (a0). | ||||
|  * @return Operand 1 OR NOT operand 2. | ||||
|  **************************************************************************/ | ||||
| inline uint32_t __attribute__ ((always_inline)) 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 ("" : [output] "=r" (result) : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); | ||||
|  | ||||
|   // orn a0, a0, a1 | ||||
|   CUSTOM_INSTR_R2_TYPE(0b0100000, a1, a0, 0b110, a0, 0b0110011); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Bit manipulation XNOR (logical xor-negate) [B.Zbb] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @param[in] rs2 Source operand 2 (a0). | ||||
|  * @return Operand 1 XOR NOT operand 2. | ||||
|  **************************************************************************/ | ||||
| inline uint32_t __attribute__ ((always_inline)) 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 ("" : [output] "=r" (result) : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); | ||||
|  | ||||
|   // xnor a0, a0, a1 | ||||
|   CUSTOM_INSTR_R2_TYPE(0b0100000, a1, a0, 0b100, a0, 0b0110011); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Bit manipulation ROL (rotate-left) [B.Zbb] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @param[in] rs2 Source operand 2 (a0). | ||||
|  * @return Operand 1 rotated left by operand_2(4:0) positions. | ||||
|  **************************************************************************/ | ||||
| inline uint32_t __attribute__ ((always_inline)) 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 ("" : [output] "=r" (result) : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); | ||||
|  | ||||
|   // rol a0, a0, a1 | ||||
|   CUSTOM_INSTR_R2_TYPE(0b0110000, a1, a0, 0b001, a0, 0b0110011); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Bit manipulation ROR (rotate-right) [B.Zbb] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @param[in] rs2 Source operand 2 (a0). | ||||
|  * @return Operand 1 rotated right by operand_2(4:0) positions. | ||||
|  **************************************************************************/ | ||||
| inline uint32_t __attribute__ ((always_inline)) 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 ("" : [output] "=r" (result) : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); | ||||
|  | ||||
|   // ror a0, a0, a1 | ||||
|   CUSTOM_INSTR_R2_TYPE(0b0110000, a1, a0, 0b101, a0, 0b0110011); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Bit manipulation RORI (rotate-right) by 20 positions. [B.Zbb] | ||||
|  * @warning Fixed shift amount (20) for now. | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @return Operand 1 rotated right by 20 positions. | ||||
|  **************************************************************************/ | ||||
| inline uint32_t __attribute__ ((always_inline)) 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 ("" : [output] "=r" (result) : [input_i] "r" (tmp_a)); | ||||
|  | ||||
|   // rori a0, a0, 20 | ||||
|   CUSTOM_INSTR_R1_TYPE(0b0110000, 0b10100, a0, 0b101, a0, 0b0010011); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Bit manipulation ORC.B (or-combine byte) [B.Zbb] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @return OR-combined bytes of operand 1. | ||||
|  **************************************************************************/ | ||||
| inline uint32_t __attribute__ ((always_inline)) 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 ("" : [output] "=r" (result) : [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); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Bit manipulation REV8 (byte-swap) [B.Zbb] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @return Byte swap of operand 1 | ||||
|  **************************************************************************/ | ||||
| inline uint32_t __attribute__ ((always_inline)) 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 ("" : [output] "=r" (result) : [input_i] "r" (tmp_a)); | ||||
|  | ||||
|   // grevi a0, a0, -8 (pseudo-instruction: rev8 a0, a0) | ||||
|   CUSTOM_INSTR_R1_TYPE(0b0110100, 0b11000, a0, 0b101, a0, 0b0010011); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
|  | ||||
| // ================================================================================================ | ||||
| // Zbb - Base instructions | ||||
| // ================================================================================================ | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Address generation instructions SH1ADD (add with logical-1-shift) [B.Zba] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @param[in] rs2 Source operand 2 (a0). | ||||
|  * @return Operand 2 + (Operand 1 << 1) | ||||
|  **************************************************************************/ | ||||
| inline uint32_t __attribute__ ((always_inline)) 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 ("" : [output] "=r" (result) : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); | ||||
|  | ||||
|   // sh1add a0, a0, a1 | ||||
|   CUSTOM_INSTR_R2_TYPE(0b0010000, a1, a0, 0b010, a0, 0b0110011); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Address generation instructions SH2ADD (add with logical-2-shift) [B.Zba] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @param[in] rs2 Source operand 2 (a0). | ||||
|  * @return Operand 2 + (Operand 1 << 2) | ||||
|  **************************************************************************/ | ||||
| inline uint32_t __attribute__ ((always_inline)) 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 ("" : [output] "=r" (result) : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); | ||||
|  | ||||
|   // sh2add a0, a0, a1 | ||||
|   CUSTOM_INSTR_R2_TYPE(0b0010000, a1, a0, 0b100, a0, 0b0110011); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Address generation instructions SH1ADD (add with logical-3-shift) [B.Zba] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @param[in] rs2 Source operand 2 (a0). | ||||
|  * @return Operand 2 + (Operand 1 << 3) | ||||
|  **************************************************************************/ | ||||
| inline uint32_t __attribute__ ((always_inline)) 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 ("" : [output] "=r" (result) : [input_i] "r" (tmp_a), [input_j] "r" (tmp_b)); | ||||
|  | ||||
|   // sh3add a0, a0, a1 | ||||
|   CUSTOM_INSTR_R2_TYPE(0b0010000, a1, a0, 0b110, a0, 0b0110011); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| // ################################################################################################ | ||||
| // Emulation functions | ||||
| // ################################################################################################ | ||||
|  | ||||
|  | ||||
| // ================================================================================================ | ||||
| // Zbb - Base instructions | ||||
| // ================================================================================================ | ||||
|  | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Bit manipulation CLZ (count leading zeros) [emulation] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @return Number of leading zeros in source operand. | ||||
|  **************************************************************************/ | ||||
| uint32_t riscv_emulate_clz(uint32_t rs1) { | ||||
|  | ||||
|   uint32_t sreg = rs1; | ||||
|   uint32_t cnt = 0; | ||||
|  | ||||
|   while(1) { | ||||
|     if (sreg & 0x80000000UL) { | ||||
|       break; | ||||
|     } | ||||
|     else { | ||||
|       sreg <<= 1; | ||||
|       cnt++; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return cnt; | ||||
| } | ||||
|  | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Bit manipulation CTZ (count trailing zeros) [emulation] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @return Number of trailing zeros in source operand. | ||||
|  **************************************************************************/ | ||||
| uint32_t riscv_emulate_ctz(uint32_t rs1) { | ||||
|  | ||||
|   uint32_t sreg = rs1; | ||||
|   uint32_t cnt = 0; | ||||
|  | ||||
|   while(1) { | ||||
|     if (sreg & 1) { | ||||
|       break; | ||||
|     } | ||||
|     else { | ||||
|       sreg >>= 1; | ||||
|       cnt++; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return cnt; | ||||
| } | ||||
|  | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Bit manipulation CPOP (population count) [emulation] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @return Number of set bits in source operand. | ||||
|  **************************************************************************/ | ||||
| uint32_t riscv_emulate_cpop(uint32_t rs1) { | ||||
|  | ||||
|   uint32_t sreg = rs1; | ||||
|   uint32_t cnt = 0; | ||||
|   int i; | ||||
|  | ||||
|   for (i=0; i<32; i++) { | ||||
|     if (sreg & 1) { | ||||
|       cnt++; | ||||
|     } | ||||
|     sreg >>= 1; | ||||
|   } | ||||
|  | ||||
|   return cnt; | ||||
| } | ||||
|  | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Bit manipulation SEXT.B (sign-extend byte) [emulation] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @return Sign-extended byte (operand(7:0)). | ||||
|  **************************************************************************/ | ||||
| uint32_t riscv_emulate_sextb(uint32_t rs1) { | ||||
|  | ||||
|   uint32_t tmp = rs1 & 0xff; | ||||
|  | ||||
|   if (tmp & 0x80) { | ||||
|     tmp |= 0xFFFFFF00UL; | ||||
|   } | ||||
|  | ||||
|   return tmp; | ||||
| } | ||||
|  | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Bit manipulation SEXT.H (sign-extend half-word) [emulation] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @return Sign-extended half-word (operand(15:0)). | ||||
|  **************************************************************************/ | ||||
| uint32_t riscv_emulate_sexth(uint32_t rs1) { | ||||
|  | ||||
|   uint32_t tmp = rs1 & 0xffff; | ||||
|  | ||||
|   if (tmp & 0x8000) { | ||||
|     tmp |= 0xFFFF0000UL; | ||||
|   } | ||||
|  | ||||
|   return tmp; | ||||
| } | ||||
|  | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Bit manipulation ZEXT.H (zero-extend half-word) [emulation] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @return Zero-extended half-word (operand(15:0)). | ||||
|  **************************************************************************/ | ||||
| uint32_t riscv_emulate_zexth(uint32_t rs1) { | ||||
|  | ||||
|   return rs1 & 0x0000FFFFUL; | ||||
| } | ||||
|  | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Bit manipulation MIN (select signed minimum) [emulation] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @param[in] rs2 Source operand 1 (a0). | ||||
|  * @return Signed minimum. | ||||
|  **************************************************************************/ | ||||
| uint32_t riscv_emulate_min(uint32_t rs1, uint32_t rs2) { | ||||
|  | ||||
|   int32_t s_opa = (int32_t)rs1; | ||||
|   int32_t s_opb = (int32_t)rs2; | ||||
|  | ||||
|   if (s_opa < s_opb) { | ||||
|     return rs1; | ||||
|   } | ||||
|   else { | ||||
|     return rs2; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Bit manipulation MINU (select unsigned minimum) [emulation] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @param[in] rs2 Source operand 1 (a0). | ||||
|  * @return Unsigned minimum. | ||||
|  **************************************************************************/ | ||||
| uint32_t riscv_emulate_minu(uint32_t rs1, uint32_t rs2) { | ||||
|  | ||||
|   if (rs1 < rs2) { | ||||
|     return rs1; | ||||
|   } | ||||
|   else { | ||||
|     return rs2; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Bit manipulation MAX (select signed maximum) [emulation] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @param[in] rs2 Source operand 1 (a0). | ||||
|  * @return Signed maximum. | ||||
|  **************************************************************************/ | ||||
| uint32_t riscv_emulate_max(uint32_t rs1, uint32_t rs2) { | ||||
|  | ||||
|   int32_t s_opa = (int32_t)rs1; | ||||
|   int32_t s_opb = (int32_t)rs2; | ||||
|  | ||||
|   if (s_opa < s_opb) { | ||||
|     return rs2; | ||||
|   } | ||||
|   else { | ||||
|     return rs1; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Bit manipulation MAXU (select unsigned maximum) [emulation] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @param[in] rs2 Source operand 1 (a0). | ||||
|  * @return Unsigned maximum. | ||||
|  **************************************************************************/ | ||||
| uint32_t riscv_emulate_maxu(uint32_t rs1, uint32_t rs2) { | ||||
|  | ||||
|   if (rs1 < rs2) { | ||||
|     return rs2; | ||||
|   } | ||||
|   else { | ||||
|     return rs1; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Bit manipulation ANDN (logical and-negate) [emulation] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @param[in] rs2 Source operand 1 (a0). | ||||
|  * @return Operand 1 AND NOT operand 2. | ||||
|  **************************************************************************/ | ||||
| uint32_t riscv_emulate_andn(uint32_t rs1, uint32_t rs2) { | ||||
|  | ||||
|   return rs1 & (~rs2); | ||||
| } | ||||
|  | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Bit manipulation ORN (logical or-negate) [emulation] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @param[in] rs2 Source operand 1 (a0). | ||||
|  * @return Operand 1 OR NOT operand 2. | ||||
|  **************************************************************************/ | ||||
| uint32_t riscv_emulate_orn(uint32_t rs1, uint32_t rs2) { | ||||
|  | ||||
|   return rs1 | (~rs2); | ||||
| } | ||||
|  | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Bit manipulation XNOR (logical xor-negate) [emulation] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @param[in] rs2 Source operand 1 (a0). | ||||
|  * @return Operand 1 XOR NOT operand 2. | ||||
|  **************************************************************************/ | ||||
| uint32_t riscv_emulate_xnor(uint32_t rs1, uint32_t rs2) { | ||||
|  | ||||
|   return rs1 ^ (~rs2); | ||||
| } | ||||
|  | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Bit manipulation ROL (rotate-left) [emulation] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @param[in] rs2 Source operand 1 (a0). | ||||
|  * @return Operand 1 rotated left by operand_2(4:0) positions. | ||||
|  **************************************************************************/ | ||||
| uint32_t riscv_emulate_rol(uint32_t rs1, uint32_t rs2) { | ||||
|  | ||||
|   uint32_t shamt = rs2 & 0x1f; | ||||
|  | ||||
|   uint32_t tmp_a = rs1 << shamt; | ||||
|   uint32_t tmp_b = rs1 >> (32-shamt); | ||||
|  | ||||
|   return tmp_a | tmp_b; | ||||
| } | ||||
|  | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Bit manipulation ROR (rotate-right) [emulation] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @param[in] rs2 Source operand 1 (a0). | ||||
|  * @return Operand 1 rotated right by operand_2(4:0) positions. | ||||
|  **************************************************************************/ | ||||
| uint32_t riscv_emulate_ror(uint32_t rs1, uint32_t rs2) { | ||||
|  | ||||
|   uint32_t shamt = rs2 & 0x1f; | ||||
|  | ||||
|   uint32_t tmp_a = rs1 >> shamt; | ||||
|   uint32_t tmp_b = rs1 << (32-shamt); | ||||
|  | ||||
|   return tmp_a | tmp_b; | ||||
| } | ||||
|  | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Bit manipulation REV8 (byte swap) [emulation] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @return Operand 1 byte swapped. | ||||
|  **************************************************************************/ | ||||
| uint32_t riscv_emulate_rev8(uint32_t rs1) { | ||||
|  | ||||
|   uint32_t tmp_a = (rs1 & 0x000000ffUL) << 24; | ||||
|   uint32_t tmp_b = (rs1 & 0x0000ff00UL) << 8; | ||||
|   uint32_t tmp_c = (rs1 & 0x00ff0000UL) >> 8; | ||||
|   uint32_t tmp_d = (rs1 & 0xff000000UL) >> 24; | ||||
|  | ||||
|   return tmp_a | tmp_b | tmp_c | tmp_d; | ||||
| } | ||||
|  | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Bit manipulation ORCB (or-combine bytes) [emulation] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @return OR-combined bytes of operand 1. | ||||
|  **************************************************************************/ | ||||
| uint32_t riscv_emulate_orcb(uint32_t rs1) { | ||||
|  | ||||
|   uint32_t tmp = 0; | ||||
|  | ||||
|   if (rs1 & 0x000000ffUL) { | ||||
|     tmp |= 0x000000ffUL; | ||||
|   } | ||||
|   if (rs1 & 0x0000ff00UL) { | ||||
|     tmp |= 0x0000ff00UL; | ||||
|   } | ||||
|   if (rs1 & 0x00ff0000UL) { | ||||
|     tmp |= 0x00ff0000UL; | ||||
|   } | ||||
|   if (rs1 & 0xff000000UL) { | ||||
|     tmp |= 0xff000000UL; | ||||
|   } | ||||
|  | ||||
|   return tmp; | ||||
| } | ||||
|  | ||||
|  | ||||
| // ================================================================================================ | ||||
| // Zba - Address generation instructions | ||||
| // ================================================================================================ | ||||
|  | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Address generation instructions SH1ADD (add with logical-1-shift) [emulation] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @param[in] rs2 Source operand 1 (a0). | ||||
|  * @return Operand 2 + (Operand 1 << 1) | ||||
|  **************************************************************************/ | ||||
| uint32_t riscv_emulate_sh1add(uint32_t rs1, uint32_t rs2) { | ||||
|  | ||||
|   return rs2 + (rs1 << 1); | ||||
| } | ||||
|  | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Address generation instructions SH2ADD (add with logical-2-shift) [emulation] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @param[in] rs2 Source operand 1 (a0). | ||||
|  * @return Operand 2 + (Operand 1 << 2) | ||||
|  **************************************************************************/ | ||||
| uint32_t riscv_emulate_sh2add(uint32_t rs1, uint32_t rs2) { | ||||
|  | ||||
|   return rs2 + (rs1 << 2); | ||||
| } | ||||
|  | ||||
|  | ||||
| /**********************************************************************//** | ||||
|  * Intrinsic: Address generation instructions SH3ADD (add with logical-3-shift) [emulation] | ||||
|  * | ||||
|  * @param[in] rs1 Source operand 1 (a0). | ||||
|  * @param[in] rs2 Source operand 1 (a0). | ||||
|  * @return Operand 2 + (Operand 1 << 3) | ||||
|  **************************************************************************/ | ||||
| uint32_t riscv_emulate_sh3add(uint32_t rs1, uint32_t rs2) { | ||||
|  | ||||
|   return rs2 + (rs1 << 3); | ||||
| } | ||||
|  | ||||
|  | ||||
| #endif // neorv32_b_extension_intrinsics_h | ||||
		Reference in New Issue
	
	Block a user