Line 4... |
Line 4... |
// # The intrinsics provided by this library allow to use the hardware bit manipulation unit of #
|
// # 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. #
|
// # the RISC-V B CPU extension without the need for support by the compiler. #
|
// # ********************************************************************************************* #
|
// # ********************************************************************************************* #
|
// # BSD 3-Clause License #
|
// # BSD 3-Clause License #
|
// # #
|
// # #
|
// # Copyright (c) 2021, Stephan Nolting. All rights reserved. #
|
// # Copyright (c) 2022, Stephan Nolting. All rights reserved. #
|
// # #
|
// # #
|
// # Redistribution and use in source and binary forms, with or without modification, are #
|
// # Redistribution and use in source and binary forms, with or without modification, are #
|
// # permitted provided that the following conditions are met: #
|
// # permitted provided that the following conditions are met: #
|
// # #
|
// # #
|
// # 1. Redistributions of source code must retain the above copyright notice, this list of #
|
// # 1. Redistributions of source code must retain the above copyright notice, this list of #
|
Line 59... |
Line 59... |
// ================================================================================================
|
// ================================================================================================
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Intrinsic: Bit manipulation CLZ (count leading zeros) [B.Zbb]
|
* Intrinsic: Bit manipulation CLZ (count leading zeros) [B.Zbb]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @return Number of leading zeros in source operand.
|
* @return Number of leading zeros in source operand.
|
**************************************************************************/
|
**************************************************************************/
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_clz(uint32_t rs1) {
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_clz(uint32_t rs1) {
|
|
|
register uint32_t result __asm__ ("a0");
|
return CUSTOM_INSTR_R1_TYPE(0b0110000, 0b00000, rs1, 0b001, 0b0010011);
|
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]
|
* Intrinsic: Bit manipulation CTZ (count trailing zeros) [B.Zbb]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @return Number of trailing zeros in source operand.
|
* @return Number of trailing zeros in source operand.
|
**************************************************************************/
|
**************************************************************************/
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_ctz(uint32_t rs1) {
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_ctz(uint32_t rs1) {
|
|
|
register uint32_t result __asm__ ("a0");
|
return CUSTOM_INSTR_R1_TYPE(0b0110000, 0b00001, rs1, 0b001, 0b0010011);
|
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]
|
* Intrinsic: Bit manipulation CPOP (count set bits) [B.Zbb]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @return Number of set bits in source operand.
|
* @return Number of set bits in source operand.
|
**************************************************************************/
|
**************************************************************************/
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_cpop(uint32_t rs1) {
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_cpop(uint32_t rs1) {
|
|
|
register uint32_t result __asm__ ("a0");
|
return CUSTOM_INSTR_R1_TYPE(0b0110000, 0b00010, rs1, 0b001, 0b0010011);
|
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]
|
* Intrinsic: Bit manipulation SEXT.B (sign-extend byte) [B.Zbb]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @return Sign extended byte (operand(7:0)).
|
* @return Sign extended byte (operand(7:0)).
|
**************************************************************************/
|
**************************************************************************/
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_sextb(uint32_t rs1) {
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_sextb(uint32_t rs1) {
|
|
|
register uint32_t result __asm__ ("a0");
|
return CUSTOM_INSTR_R1_TYPE(0b0110000, 0b00100, rs1, 0b001, 0b0010011);
|
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]
|
* Intrinsic: Bit manipulation SEXT.H (sign-extend half-word) [B.Zbb]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @return Sign-extended half-word (operand(15:0)).
|
* @return Sign-extended half-word (operand(15:0)).
|
**************************************************************************/
|
**************************************************************************/
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_sexth(uint32_t rs1) {
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_sexth(uint32_t rs1) {
|
|
|
register uint32_t result __asm__ ("a0");
|
return CUSTOM_INSTR_R1_TYPE(0b0110000, 0b00101, rs1, 0b001, 0b0010011);
|
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]
|
* Intrinsic: Bit manipulation ZEXT.H (zero-extend half-word) [B.Zbb]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @return Zero-extended half-word (operand(15:0)).
|
* @return Zero-extended half-word (operand(15:0)).
|
**************************************************************************/
|
**************************************************************************/
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_zexth(uint32_t rs1) {
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_zexth(uint32_t rs1) {
|
|
|
register uint32_t result __asm__ ("a0");
|
return CUSTOM_INSTR_R1_TYPE(0b0000100, 0b00000, rs1, 0b100, 0b0110011);
|
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]
|
* Intrinsic: Bit manipulation MIN (select signed minimum) [B.Zbb]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @param[in] rs2 Source operand 2 (a0).
|
* @param[in] rs2 Source operand 2.
|
* @return Signed minimum.
|
* @return Signed minimum.
|
**************************************************************************/
|
**************************************************************************/
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_min(uint32_t rs1, uint32_t rs2) {
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_min(uint32_t rs1, uint32_t rs2) {
|
|
|
register uint32_t result __asm__ ("a0");
|
return CUSTOM_INSTR_R2_TYPE(0b0000101, rs2, rs1, 0b100, 0b0110011);
|
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]
|
* Intrinsic: Bit manipulation MINU (select unsigned minimum) [B.Zbb]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @param[in] rs2 Source operand 2 (a0).
|
* @param[in] rs2 Source operand 2.
|
* @return Unsigned minimum.
|
* @return Unsigned minimum.
|
**************************************************************************/
|
**************************************************************************/
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_minu(uint32_t rs1, uint32_t rs2) {
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_minu(uint32_t rs1, uint32_t rs2) {
|
|
|
register uint32_t result __asm__ ("a0");
|
return CUSTOM_INSTR_R2_TYPE(0b0000101, rs2, rs1, 0b101, 0b0110011);
|
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]
|
* Intrinsic: Bit manipulation MAX (select signed maximum) [B.Zbb]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @param[in] rs2 Source operand 2 (a0).
|
* @param[in] rs2 Source operand 2.
|
* @return Signed maximum.
|
* @return Signed maximum.
|
**************************************************************************/
|
**************************************************************************/
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_max(uint32_t rs1, uint32_t rs2) {
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_max(uint32_t rs1, uint32_t rs2) {
|
|
|
register uint32_t result __asm__ ("a0");
|
return CUSTOM_INSTR_R2_TYPE(0b0000101, rs2, rs1, 0b110, 0b0110011);
|
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]
|
* Intrinsic: Bit manipulation MAXU (select unsigned maximum) [B.Zbb]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @param[in] rs2 Source operand 2 (a0).
|
* @param[in] rs2 Source operand 2.
|
* @return Unsigned maximum.
|
* @return Unsigned maximum.
|
**************************************************************************/
|
**************************************************************************/
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_maxu(uint32_t rs1, uint32_t rs2) {
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_maxu(uint32_t rs1, uint32_t rs2) {
|
|
|
register uint32_t result __asm__ ("a0");
|
return CUSTOM_INSTR_R2_TYPE(0b0000101, rs2, rs1, 0b111, 0b0110011);
|
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]
|
* Intrinsic: Bit manipulation ANDN (logical and-negate) [B.Zbb]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @param[in] rs2 Source operand 2 (a0).
|
* @param[in] rs2 Source operand 2.
|
* @return Operand 1 AND NOT operand 2.
|
* @return Operand 1 AND NOT operand 2.
|
**************************************************************************/
|
**************************************************************************/
|
inline inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_andn(uint32_t rs1, uint32_t rs2) {
|
inline inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_andn(uint32_t rs1, uint32_t rs2) {
|
|
|
register uint32_t result __asm__ ("a0");
|
return CUSTOM_INSTR_R2_TYPE(0b0100000, rs2, rs1, 0b111, 0b0110011);
|
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]
|
* Intrinsic: Bit manipulation ORN (logical or-negate) [B.Zbb]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @param[in] rs2 Source operand 2 (a0).
|
* @param[in] rs2 Source operand 2.
|
* @return Operand 1 OR NOT operand 2.
|
* @return Operand 1 OR NOT operand 2.
|
**************************************************************************/
|
**************************************************************************/
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_orn(uint32_t rs1, uint32_t rs2) {
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_orn(uint32_t rs1, uint32_t rs2) {
|
|
|
register uint32_t result __asm__ ("a0");
|
return CUSTOM_INSTR_R2_TYPE(0b0100000, rs2, rs1, 0b110, 0b0110011);
|
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]
|
* Intrinsic: Bit manipulation XNOR (logical xor-negate) [B.Zbb]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @param[in] rs2 Source operand 2 (a0).
|
* @param[in] rs2 Source operand 2.
|
* @return Operand 1 XOR NOT operand 2.
|
* @return Operand 1 XOR NOT operand 2.
|
**************************************************************************/
|
**************************************************************************/
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_xnor(uint32_t rs1, uint32_t rs2) {
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_xnor(uint32_t rs1, uint32_t rs2) {
|
|
|
register uint32_t result __asm__ ("a0");
|
return CUSTOM_INSTR_R2_TYPE(0b0100000, rs2, rs1, 0b100, 0b0110011);
|
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]
|
* Intrinsic: Bit manipulation ROL (rotate-left) [B.Zbb]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @param[in] rs2 Source operand 2 (a0).
|
* @param[in] rs2 Source operand 2.
|
* @return Operand 1 rotated left by operand_2(4:0) positions.
|
* @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) {
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_rol(uint32_t rs1, uint32_t rs2) {
|
|
|
register uint32_t result __asm__ ("a0");
|
return CUSTOM_INSTR_R2_TYPE(0b0110000, rs2, rs1, 0b001, 0b0110011);
|
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]
|
* Intrinsic: Bit manipulation ROR (rotate-right) [B.Zbb]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @param[in] rs2 Source operand 2 (a0).
|
* @param[in] rs2 Source operand 2.
|
* @return Operand 1 rotated right by operand_2(4:0) positions.
|
* @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) {
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_ror(uint32_t rs1, uint32_t rs2) {
|
|
|
register uint32_t result __asm__ ("a0");
|
return CUSTOM_INSTR_R2_TYPE(0b0110000, rs2, rs1, 0b101, 0b0110011);
|
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]
|
* Intrinsic: Bit manipulation RORI (rotate-right) by 20 positions. [B.Zbb]
|
* @warning Fixed shift amount (20) for now.
|
* @warning Fixed shift amount (20) for now.
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @return Operand 1 rotated right by 20 positions.
|
* @return Operand 1 rotated right by 20 positions.
|
**************************************************************************/
|
**************************************************************************/
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_rori20(uint32_t rs1) {
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_rori20(uint32_t rs1) {
|
|
|
register uint32_t result __asm__ ("a0");
|
return CUSTOM_INSTR_R1_TYPE(0b0110000, 0b10100, rs1, 0b101, 0b0010011);
|
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]
|
* Intrinsic: Bit manipulation ORC.B (or-combine byte) [B.Zbb]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @return OR-combined bytes of operand 1.
|
* @return OR-combined bytes of operand 1.
|
**************************************************************************/
|
**************************************************************************/
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_orcb(uint32_t rs1) {
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_orcb(uint32_t rs1) {
|
|
|
register uint32_t result __asm__ ("a0");
|
return CUSTOM_INSTR_R1_TYPE(0b0010100, 0b00111, rs1, 0b101, 0b0010011);
|
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]
|
* Intrinsic: Bit manipulation REV8 (byte-swap) [B.Zbb]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @return Byte swap of operand 1
|
* @return Byte swap of operand 1
|
**************************************************************************/
|
**************************************************************************/
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_rev8(uint32_t rs1) {
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_rev8(uint32_t rs1) {
|
|
|
register uint32_t result __asm__ ("a0");
|
return CUSTOM_INSTR_R1_TYPE(0b0110100, 0b11000, rs1, 0b101, 0b0010011);
|
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
|
// Zba - Address-generation instructions
|
// ================================================================================================
|
// ================================================================================================
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Intrinsic: Address generation instructions SH1ADD (add with logical-1-shift) [B.Zba]
|
* Intrinsic: Address generation instructions SH1ADD (add with logical-1-shift) [B.Zba]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @param[in] rs2 Source operand 2 (a0).
|
* @param[in] rs2 Source operand 2.
|
* @return Operand 2 + (Operand 1 << 1)
|
* @return Operand 2 + (Operand 1 << 1)
|
**************************************************************************/
|
**************************************************************************/
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_sh1add(uint32_t rs1, uint32_t rs2) {
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_sh1add(uint32_t rs1, uint32_t rs2) {
|
|
|
register uint32_t result __asm__ ("a0");
|
return CUSTOM_INSTR_R2_TYPE(0b0010000, rs2, rs1, 0b010, 0b0110011);
|
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]
|
* Intrinsic: Address generation instructions SH2ADD (add with logical-2-shift) [B.Zba]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @param[in] rs2 Source operand 2 (a0).
|
* @param[in] rs2 Source operand 2.
|
* @return Operand 2 + (Operand 1 << 2)
|
* @return Operand 2 + (Operand 1 << 2)
|
**************************************************************************/
|
**************************************************************************/
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_sh2add(uint32_t rs1, uint32_t rs2) {
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_sh2add(uint32_t rs1, uint32_t rs2) {
|
|
|
register uint32_t result __asm__ ("a0");
|
return CUSTOM_INSTR_R2_TYPE(0b0010000, rs2, rs1, 0b100, 0b0110011);
|
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]
|
* Intrinsic: Address generation instructions SH1ADD (add with logical-3-shift) [B.Zba]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @param[in] rs2 Source operand 2 (a0).
|
* @param[in] rs2 Source operand 2.
|
* @return Operand 2 + (Operand 1 << 3)
|
* @return Operand 2 + (Operand 1 << 3)
|
**************************************************************************/
|
**************************************************************************/
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_sh3add(uint32_t rs1, uint32_t rs2) {
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_sh3add(uint32_t rs1, uint32_t rs2) {
|
|
|
register uint32_t result __asm__ ("a0");
|
return CUSTOM_INSTR_R2_TYPE(0b0010000, rs2, rs1, 0b110, 0b0110011);
|
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));
|
// Zbs - Single-bit instructions
|
|
// ================================================================================================
|
|
|
// sh3add a0, a0, a1
|
|
CUSTOM_INSTR_R2_TYPE(0b0010000, a1, a0, 0b110, a0, 0b0110011);
|
|
|
|
return result;
|
/**********************************************************************//**
|
|
* Intrinsic: Bit manipulation BCLR (bit-clear) [B.Zbs]
|
|
*
|
|
* @param[in] rs1 Source operand 1.
|
|
* @param[in] rs2 Source operand 2.
|
|
* @return Operand 1 with bit cleared indexed by operand_2(4:0).
|
|
**************************************************************************/
|
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_bclr(uint32_t rs1, uint32_t rs2) {
|
|
|
|
return CUSTOM_INSTR_R2_TYPE(0b0100100, rs2, rs1, 0b001, 0b0110011);
|
|
}
|
|
|
|
|
|
/**********************************************************************//**
|
|
* Intrinsic: Bit manipulation BCLRI (bit-clear) by 20 positions. [B.Zbs]
|
|
* @warning Fixed shift amount (20) for now.
|
|
*
|
|
* @param[in] rs1 Source operand 1.
|
|
* @return Operand 1 with bit cleared at position 20.
|
|
**************************************************************************/
|
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_bclri20(uint32_t rs1) {
|
|
|
|
return CUSTOM_INSTR_R1_TYPE(0b0100100, 0b10100, rs1, 0b001, 0b0010011);
|
|
}
|
|
|
|
|
|
/**********************************************************************//**
|
|
* Intrinsic: Bit manipulation BEXT (bit-extract) [B.Zbs]
|
|
*
|
|
* @param[in] rs1 Source operand 1.
|
|
* @param[in] rs2 Source operand 2.
|
|
* @return Extract bit from Operand 1 indexed by operand_2(4:0).
|
|
**************************************************************************/
|
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_bext(uint32_t rs1, uint32_t rs2) {
|
|
|
|
return CUSTOM_INSTR_R2_TYPE(0b0100100, rs2, rs1, 0b101, 0b0110011);
|
|
}
|
|
|
|
|
|
/**********************************************************************//**
|
|
* Intrinsic: Bit manipulation BEXTI (bit-extract) by 20 positions. [B.Zbs]
|
|
* @warning Fixed shift amount (20) for now.
|
|
*
|
|
* @param[in] rs1 Source operand 1.
|
|
* @return Extract bit from Operand 1 at position 20.
|
|
**************************************************************************/
|
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_bexti20(uint32_t rs1) {
|
|
|
|
return CUSTOM_INSTR_R1_TYPE(0b0100100, 0b10100, rs1, 0b101, 0b0010011);
|
|
}
|
|
|
|
|
|
/**********************************************************************//**
|
|
* Intrinsic: Bit manipulation BINV (bit-invert) [B.Zbs]
|
|
*
|
|
* @param[in] rs1 Source operand 1.
|
|
* @param[in] rs2 Source operand 2.
|
|
* @return Invert bit from Operand 1 indexed by operand_2(4:0).
|
|
**************************************************************************/
|
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_binv(uint32_t rs1, uint32_t rs2) {
|
|
|
|
return CUSTOM_INSTR_R2_TYPE(0b0110100, rs2, rs1, 0b001, 0b0110011);
|
}
|
}
|
|
|
|
|
|
/**********************************************************************//**
|
|
* Intrinsic: Bit manipulation BINVI (bit-invert) by 20 positions. [B.Zbs]
|
|
* @warning Fixed shift amount (20) for now.
|
|
*
|
|
* @param[in] rs1 Source operand 1.
|
|
* @return Invert bit from Operand 1 at position 20.
|
|
**************************************************************************/
|
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_binvi20(uint32_t rs1) {
|
|
|
|
return CUSTOM_INSTR_R1_TYPE(0b0110100, 0b10100, rs1, 0b001, 0b0010011);
|
|
}
|
|
|
|
|
|
/**********************************************************************//**
|
|
* Intrinsic: Bit manipulation BSET (bit-set) [B.Zbs]
|
|
*
|
|
* @param[in] rs1 Source operand 1.
|
|
* @param[in] rs2 Source operand 2.
|
|
* @return set bit from Operand 1 indexed by operand_2(4:0).
|
|
**************************************************************************/
|
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_bset(uint32_t rs1, uint32_t rs2) {
|
|
|
|
return CUSTOM_INSTR_R2_TYPE(0b0010100, rs2, rs1, 0b001, 0b0110011);
|
|
}
|
|
|
|
|
|
/**********************************************************************//**
|
|
* Intrinsic: Bit manipulation BSETI (bit-set) by 20 positions. [B.Zbs]
|
|
* @warning Fixed shift amount (20) for now.
|
|
*
|
|
* @param[in] rs1 Source operand 1.
|
|
* @return Set bit from Operand 1 at position 20.
|
|
**************************************************************************/
|
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_bseti20(uint32_t rs1) {
|
|
|
|
return CUSTOM_INSTR_R1_TYPE(0b0010100, 0b10100, rs1, 0b001, 0b0010011);
|
|
}
|
|
|
|
|
|
// ================================================================================================
|
|
// Zbc - Carry-less multiplication instructions
|
|
// ================================================================================================
|
|
|
|
|
|
/**********************************************************************//**
|
|
* Intrinsic: Bit manipulation CLMUL (carry-less multiplication, low-part) [B.Zbc]
|
|
*
|
|
* @param[in] rs1 Source operand 1.
|
|
* @param[in] rs2 Source operand 2.
|
|
* @return Carry-less product, low part.
|
|
**************************************************************************/
|
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_clmul(uint32_t rs1, uint32_t rs2) {
|
|
|
|
return CUSTOM_INSTR_R2_TYPE(0b0000101, rs2, rs1, 0b001, 0b0110011);
|
|
}
|
|
|
|
|
|
/**********************************************************************//**
|
|
* Intrinsic: Bit manipulation CLMULH (carry-less multiplication, high-part) [B.Zbc]
|
|
*
|
|
* @param[in] rs1 Source operand 1.
|
|
* @param[in] rs2 Source operand 2.
|
|
* @return Carry-less product, high part.
|
|
**************************************************************************/
|
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_clmulh(uint32_t rs1, uint32_t rs2) {
|
|
|
|
return CUSTOM_INSTR_R2_TYPE(0b0000101, rs2, rs1, 0b011, 0b0110011);
|
|
}
|
|
|
|
|
|
/**********************************************************************//**
|
|
* Intrinsic: Bit manipulation CLMULR (carry-less multiplication, reversed) [B.Zbc]
|
|
*
|
|
* @param[in] rs1 Source operand 1.
|
|
* @param[in] rs2 Source operand 2.
|
|
* @return Carry-less product, low part, reversed.
|
|
**************************************************************************/
|
|
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_clmulr(uint32_t rs1, uint32_t rs2) {
|
|
|
|
return CUSTOM_INSTR_R2_TYPE(0b0000101, rs1, rs2, 0b010, 0b0110011);
|
|
}
|
|
|
|
|
// ################################################################################################
|
// ################################################################################################
|
// Emulation functions
|
// Emulation functions
|
// ################################################################################################
|
// ################################################################################################
|
|
|
Line 539... |
Line 490... |
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Intrinsic: Bit manipulation CLZ (count leading zeros) [emulation]
|
* Intrinsic: Bit manipulation CLZ (count leading zeros) [emulation]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @return Number of leading zeros in source operand.
|
* @return Number of leading zeros in source operand.
|
**************************************************************************/
|
**************************************************************************/
|
uint32_t riscv_emulate_clz(uint32_t rs1) {
|
uint32_t riscv_emulate_clz(uint32_t rs1) {
|
|
|
uint32_t sreg = rs1;
|
uint32_t sreg = rs1;
|
Line 564... |
Line 515... |
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Intrinsic: Bit manipulation CTZ (count trailing zeros) [emulation]
|
* Intrinsic: Bit manipulation CTZ (count trailing zeros) [emulation]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @return Number of trailing zeros in source operand.
|
* @return Number of trailing zeros in source operand.
|
**************************************************************************/
|
**************************************************************************/
|
uint32_t riscv_emulate_ctz(uint32_t rs1) {
|
uint32_t riscv_emulate_ctz(uint32_t rs1) {
|
|
|
uint32_t sreg = rs1;
|
uint32_t sreg = rs1;
|
Line 589... |
Line 540... |
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Intrinsic: Bit manipulation CPOP (population count) [emulation]
|
* Intrinsic: Bit manipulation CPOP (population count) [emulation]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @return Number of set bits in source operand.
|
* @return Number of set bits in source operand.
|
**************************************************************************/
|
**************************************************************************/
|
uint32_t riscv_emulate_cpop(uint32_t rs1) {
|
uint32_t riscv_emulate_cpop(uint32_t rs1) {
|
|
|
uint32_t sreg = rs1;
|
uint32_t sreg = rs1;
|
Line 612... |
Line 563... |
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Intrinsic: Bit manipulation SEXT.B (sign-extend byte) [emulation]
|
* Intrinsic: Bit manipulation SEXT.B (sign-extend byte) [emulation]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @return Sign-extended byte (operand(7:0)).
|
* @return Sign-extended byte (operand(7:0)).
|
**************************************************************************/
|
**************************************************************************/
|
uint32_t riscv_emulate_sextb(uint32_t rs1) {
|
uint32_t riscv_emulate_sextb(uint32_t rs1) {
|
|
|
uint32_t tmp = rs1 & 0xff;
|
uint32_t tmp = rs1 & 0xff;
|
Line 630... |
Line 581... |
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Intrinsic: Bit manipulation SEXT.H (sign-extend half-word) [emulation]
|
* Intrinsic: Bit manipulation SEXT.H (sign-extend half-word) [emulation]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @return Sign-extended half-word (operand(15:0)).
|
* @return Sign-extended half-word (operand(15:0)).
|
**************************************************************************/
|
**************************************************************************/
|
uint32_t riscv_emulate_sexth(uint32_t rs1) {
|
uint32_t riscv_emulate_sexth(uint32_t rs1) {
|
|
|
uint32_t tmp = rs1 & 0xffff;
|
uint32_t tmp = rs1 & 0xffff;
|
Line 648... |
Line 599... |
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Intrinsic: Bit manipulation ZEXT.H (zero-extend half-word) [emulation]
|
* Intrinsic: Bit manipulation ZEXT.H (zero-extend half-word) [emulation]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @return Zero-extended half-word (operand(15:0)).
|
* @return Zero-extended half-word (operand(15:0)).
|
**************************************************************************/
|
**************************************************************************/
|
uint32_t riscv_emulate_zexth(uint32_t rs1) {
|
uint32_t riscv_emulate_zexth(uint32_t rs1) {
|
|
|
return rs1 & 0x0000FFFFUL;
|
return rs1 & 0x0000FFFFUL;
|
Line 660... |
Line 611... |
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Intrinsic: Bit manipulation MIN (select signed minimum) [emulation]
|
* Intrinsic: Bit manipulation MIN (select signed minimum) [emulation]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @param[in] rs2 Source operand 1 (a0).
|
* @param[in] rs2 Source operand 1.
|
* @return Signed minimum.
|
* @return Signed minimum.
|
**************************************************************************/
|
**************************************************************************/
|
uint32_t riscv_emulate_min(uint32_t rs1, uint32_t rs2) {
|
uint32_t riscv_emulate_min(uint32_t rs1, uint32_t rs2) {
|
|
|
int32_t s_opa = (int32_t)rs1;
|
int32_t s_opa = (int32_t)rs1;
|
Line 681... |
Line 632... |
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Intrinsic: Bit manipulation MINU (select unsigned minimum) [emulation]
|
* Intrinsic: Bit manipulation MINU (select unsigned minimum) [emulation]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @param[in] rs2 Source operand 1 (a0).
|
* @param[in] rs2 Source operand 1.
|
* @return Unsigned minimum.
|
* @return Unsigned minimum.
|
**************************************************************************/
|
**************************************************************************/
|
uint32_t riscv_emulate_minu(uint32_t rs1, uint32_t rs2) {
|
uint32_t riscv_emulate_minu(uint32_t rs1, uint32_t rs2) {
|
|
|
if (rs1 < rs2) {
|
if (rs1 < rs2) {
|
Line 699... |
Line 650... |
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Intrinsic: Bit manipulation MAX (select signed maximum) [emulation]
|
* Intrinsic: Bit manipulation MAX (select signed maximum) [emulation]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @param[in] rs2 Source operand 1 (a0).
|
* @param[in] rs2 Source operand 1.
|
* @return Signed maximum.
|
* @return Signed maximum.
|
**************************************************************************/
|
**************************************************************************/
|
uint32_t riscv_emulate_max(uint32_t rs1, uint32_t rs2) {
|
uint32_t riscv_emulate_max(uint32_t rs1, uint32_t rs2) {
|
|
|
int32_t s_opa = (int32_t)rs1;
|
int32_t s_opa = (int32_t)rs1;
|
Line 720... |
Line 671... |
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Intrinsic: Bit manipulation MAXU (select unsigned maximum) [emulation]
|
* Intrinsic: Bit manipulation MAXU (select unsigned maximum) [emulation]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @param[in] rs2 Source operand 1 (a0).
|
* @param[in] rs2 Source operand 1.
|
* @return Unsigned maximum.
|
* @return Unsigned maximum.
|
**************************************************************************/
|
**************************************************************************/
|
uint32_t riscv_emulate_maxu(uint32_t rs1, uint32_t rs2) {
|
uint32_t riscv_emulate_maxu(uint32_t rs1, uint32_t rs2) {
|
|
|
if (rs1 < rs2) {
|
if (rs1 < rs2) {
|
Line 738... |
Line 689... |
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Intrinsic: Bit manipulation ANDN (logical and-negate) [emulation]
|
* Intrinsic: Bit manipulation ANDN (logical and-negate) [emulation]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @param[in] rs2 Source operand 1 (a0).
|
* @param[in] rs2 Source operand 1.
|
* @return Operand 1 AND NOT operand 2.
|
* @return Operand 1 AND NOT operand 2.
|
**************************************************************************/
|
**************************************************************************/
|
uint32_t riscv_emulate_andn(uint32_t rs1, uint32_t rs2) {
|
uint32_t riscv_emulate_andn(uint32_t rs1, uint32_t rs2) {
|
|
|
return rs1 & (~rs2);
|
return rs1 & (~rs2);
|
Line 751... |
Line 702... |
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Intrinsic: Bit manipulation ORN (logical or-negate) [emulation]
|
* Intrinsic: Bit manipulation ORN (logical or-negate) [emulation]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @param[in] rs2 Source operand 1 (a0).
|
* @param[in] rs2 Source operand 1.
|
* @return Operand 1 OR NOT operand 2.
|
* @return Operand 1 OR NOT operand 2.
|
**************************************************************************/
|
**************************************************************************/
|
uint32_t riscv_emulate_orn(uint32_t rs1, uint32_t rs2) {
|
uint32_t riscv_emulate_orn(uint32_t rs1, uint32_t rs2) {
|
|
|
return rs1 | (~rs2);
|
return rs1 | (~rs2);
|
Line 764... |
Line 715... |
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Intrinsic: Bit manipulation XNOR (logical xor-negate) [emulation]
|
* Intrinsic: Bit manipulation XNOR (logical xor-negate) [emulation]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @param[in] rs2 Source operand 1 (a0).
|
* @param[in] rs2 Source operand 1.
|
* @return Operand 1 XOR NOT operand 2.
|
* @return Operand 1 XOR NOT operand 2.
|
**************************************************************************/
|
**************************************************************************/
|
uint32_t riscv_emulate_xnor(uint32_t rs1, uint32_t rs2) {
|
uint32_t riscv_emulate_xnor(uint32_t rs1, uint32_t rs2) {
|
|
|
return rs1 ^ (~rs2);
|
return rs1 ^ (~rs2);
|
Line 777... |
Line 728... |
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Intrinsic: Bit manipulation ROL (rotate-left) [emulation]
|
* Intrinsic: Bit manipulation ROL (rotate-left) [emulation]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @param[in] rs2 Source operand 1 (a0).
|
* @param[in] rs2 Source operand 1.
|
* @return Operand 1 rotated left by operand_2(4:0) positions.
|
* @return Operand 1 rotated left by operand_2(4:0) positions.
|
**************************************************************************/
|
**************************************************************************/
|
uint32_t riscv_emulate_rol(uint32_t rs1, uint32_t rs2) {
|
uint32_t riscv_emulate_rol(uint32_t rs1, uint32_t rs2) {
|
|
|
uint32_t shamt = rs2 & 0x1f;
|
uint32_t shamt = rs2 & 0x1f;
|
Line 795... |
Line 746... |
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Intrinsic: Bit manipulation ROR (rotate-right) [emulation]
|
* Intrinsic: Bit manipulation ROR (rotate-right) [emulation]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @param[in] rs2 Source operand 1 (a0).
|
* @param[in] rs2 Source operand 1.
|
* @return Operand 1 rotated right by operand_2(4:0) positions.
|
* @return Operand 1 rotated right by operand_2(4:0) positions.
|
**************************************************************************/
|
**************************************************************************/
|
uint32_t riscv_emulate_ror(uint32_t rs1, uint32_t rs2) {
|
uint32_t riscv_emulate_ror(uint32_t rs1, uint32_t rs2) {
|
|
|
uint32_t shamt = rs2 & 0x1f;
|
uint32_t shamt = rs2 & 0x1f;
|
Line 813... |
Line 764... |
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Intrinsic: Bit manipulation REV8 (byte swap) [emulation]
|
* Intrinsic: Bit manipulation REV8 (byte swap) [emulation]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @return Operand 1 byte swapped.
|
* @return Operand 1 byte swapped.
|
**************************************************************************/
|
**************************************************************************/
|
uint32_t riscv_emulate_rev8(uint32_t rs1) {
|
uint32_t riscv_emulate_rev8(uint32_t rs1) {
|
|
|
uint32_t tmp_a = (rs1 & 0x000000ffUL) << 24;
|
uint32_t tmp_a = (rs1 & 0x000000ffUL) << 24;
|
Line 830... |
Line 781... |
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Intrinsic: Bit manipulation ORCB (or-combine bytes) [emulation]
|
* Intrinsic: Bit manipulation ORCB (or-combine bytes) [emulation]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @return OR-combined bytes of operand 1.
|
* @return OR-combined bytes of operand 1.
|
**************************************************************************/
|
**************************************************************************/
|
uint32_t riscv_emulate_orcb(uint32_t rs1) {
|
uint32_t riscv_emulate_orcb(uint32_t rs1) {
|
|
|
uint32_t tmp = 0;
|
uint32_t tmp = 0;
|
Line 862... |
Line 813... |
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Intrinsic: Address generation instructions SH1ADD (add with logical-1-shift) [emulation]
|
* Intrinsic: Address generation instructions SH1ADD (add with logical-1-shift) [emulation]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @param[in] rs2 Source operand 1 (a0).
|
* @param[in] rs2 Source operand 1.
|
* @return Operand 2 + (Operand 1 << 1)
|
* @return Operand 2 + (Operand 1 << 1)
|
**************************************************************************/
|
**************************************************************************/
|
uint32_t riscv_emulate_sh1add(uint32_t rs1, uint32_t rs2) {
|
uint32_t riscv_emulate_sh1add(uint32_t rs1, uint32_t rs2) {
|
|
|
return rs2 + (rs1 << 1);
|
return rs2 + (rs1 << 1);
|
Line 875... |
Line 826... |
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Intrinsic: Address generation instructions SH2ADD (add with logical-2-shift) [emulation]
|
* Intrinsic: Address generation instructions SH2ADD (add with logical-2-shift) [emulation]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @param[in] rs2 Source operand 1 (a0).
|
* @param[in] rs2 Source operand 1.
|
* @return Operand 2 + (Operand 1 << 2)
|
* @return Operand 2 + (Operand 1 << 2)
|
**************************************************************************/
|
**************************************************************************/
|
uint32_t riscv_emulate_sh2add(uint32_t rs1, uint32_t rs2) {
|
uint32_t riscv_emulate_sh2add(uint32_t rs1, uint32_t rs2) {
|
|
|
return rs2 + (rs1 << 2);
|
return rs2 + (rs1 << 2);
|
Line 888... |
Line 839... |
|
|
|
|
/**********************************************************************//**
|
/**********************************************************************//**
|
* Intrinsic: Address generation instructions SH3ADD (add with logical-3-shift) [emulation]
|
* Intrinsic: Address generation instructions SH3ADD (add with logical-3-shift) [emulation]
|
*
|
*
|
* @param[in] rs1 Source operand 1 (a0).
|
* @param[in] rs1 Source operand 1.
|
* @param[in] rs2 Source operand 1 (a0).
|
* @param[in] rs2 Source operand 1.
|
* @return Operand 2 + (Operand 1 << 3)
|
* @return Operand 2 + (Operand 1 << 3)
|
**************************************************************************/
|
**************************************************************************/
|
uint32_t riscv_emulate_sh3add(uint32_t rs1, uint32_t rs2) {
|
uint32_t riscv_emulate_sh3add(uint32_t rs1, uint32_t rs2) {
|
|
|
return rs2 + (rs1 << 3);
|
return rs2 + (rs1 << 3);
|
}
|
}
|
|
|
|
|
|
// ================================================================================================
|
|
// Zbs - Single-bit instructions
|
|
// ================================================================================================
|
|
|
|
|
|
/**********************************************************************//**
|
|
* Intrinsic: Bit manipulation BCLR (bit-clear) [emulation]
|
|
*
|
|
* @param[in] rs1 Source operand 1.
|
|
* @param[in] rs2 Source operand 1.
|
|
* @return Operand 1 with cleared bit indexed by operand_2(4:0).
|
|
**************************************************************************/
|
|
uint32_t riscv_emulate_bclr(uint32_t rs1, uint32_t rs2) {
|
|
|
|
uint32_t shamt = rs2 & 0x1f;
|
|
uint32_t tmp = 1 << shamt;
|
|
|
|
return rs1 & (~tmp);
|
|
}
|
|
|
|
|
|
/**********************************************************************//**
|
|
* Intrinsic: Bit manipulation BEXT (bit-extract) [emulation]
|
|
*
|
|
* @param[in] rs1 Source operand 1.
|
|
* @param[in] rs2 Source operand 1.
|
|
* @return Extract bit from operand 1 indexed by operand_2(4:0).
|
|
**************************************************************************/
|
|
uint32_t riscv_emulate_bext(uint32_t rs1, uint32_t rs2) {
|
|
|
|
uint32_t shamt = rs2 & 0x1f;
|
|
uint32_t tmp = rs1 >> shamt;
|
|
|
|
return tmp & 1;
|
|
}
|
|
|
|
|
|
/**********************************************************************//**
|
|
* Intrinsic: Bit manipulation BINV (bit-invert) [emulation]
|
|
*
|
|
* @param[in] rs1 Source operand 1.
|
|
* @param[in] rs2 Source operand 1.
|
|
* @return Invert bit from operand 1 indexed by operand_2(4:0).
|
|
**************************************************************************/
|
|
uint32_t riscv_emulate_binv(uint32_t rs1, uint32_t rs2) {
|
|
|
|
uint32_t shamt = rs2 & 0x1f;
|
|
uint32_t tmp = 1 << shamt;
|
|
|
|
return rs1 ^ tmp;
|
|
}
|
|
|
|
|
|
/**********************************************************************//**
|
|
* Intrinsic: Bit manipulation BSET (bit-set) [emulation]
|
|
*
|
|
* @param[in] rs1 Source operand 1.
|
|
* @param[in] rs2 Source operand 1.
|
|
* @return Set bit from operand 1 indexed by operand_2(4:0).
|
|
**************************************************************************/
|
|
uint32_t riscv_emulate_bset(uint32_t rs1, uint32_t rs2) {
|
|
|
|
uint32_t shamt = rs2 & 0x1f;
|
|
uint32_t tmp = 1 << shamt;
|
|
|
|
return rs1 | tmp;
|
|
}
|
|
|
|
|
|
// ================================================================================================
|
|
// Zbc - Carry-less multiplication instructions
|
|
// ================================================================================================
|
|
|
|
|
|
/**********************************************************************//**
|
|
* Intrinsic: Bit manipulation CLMUL (carry-less multiply, low-part) [emulation]
|
|
*
|
|
* @param[in] rs1 Source operand 1.
|
|
* @param[in] rs2 Source operand 1.
|
|
* @return Carry-less multiplication product, low part
|
|
**************************************************************************/
|
|
uint32_t riscv_emulate_clmul(uint32_t rs1, uint32_t rs2) {
|
|
|
|
uint32_t i;
|
|
uint64_t tmp;
|
|
union {
|
|
uint64_t uint64;
|
|
uint32_t uint32[sizeof(uint64_t)/sizeof(uint32_t)];
|
|
} res;
|
|
|
|
res.uint64 = 0;
|
|
for (i=0; i<32; i++) {
|
|
if ((rs2 >> i) & 1) {
|
|
tmp = (uint64_t)rs1;
|
|
tmp = tmp << i;
|
|
res.uint64 = res.uint64 ^ tmp;
|
|
}
|
|
}
|
|
|
|
return res.uint32[0];
|
|
}
|
|
|
|
|
|
/**********************************************************************//**
|
|
* Intrinsic: Bit manipulation CLMULH (carry-less multiply, high-part) [emulation]
|
|
*
|
|
* @param[in] rs1 Source operand 1.
|
|
* @param[in] rs2 Source operand 1.
|
|
* @return Carry-less multiplication product, high part
|
|
**************************************************************************/
|
|
uint32_t riscv_emulate_clmulh(uint32_t rs1, uint32_t rs2) {
|
|
|
|
uint32_t i;
|
|
uint64_t tmp;
|
|
union {
|
|
uint64_t uint64;
|
|
uint32_t uint32[sizeof(uint64_t)/sizeof(uint32_t)];
|
|
} res;
|
|
|
|
res.uint64 = 0;
|
|
for (i=0; i<32; i++) {
|
|
if ((rs2 >> i) & 1) {
|
|
tmp = (uint64_t)rs1;
|
|
tmp = tmp << i;
|
|
res.uint64 = res.uint64 ^ tmp;
|
|
}
|
|
}
|
|
|
|
return res.uint32[1];
|
|
}
|
|
|
|
|
|
/**********************************************************************//**
|
|
* Intrinsic: Bit manipulation CLMUR (carry-less multiply, reversed) [emulation]
|
|
*
|
|
* @param[in] rs1 Source operand 1.
|
|
* @param[in] rs2 Source operand 1.
|
|
* @return Carry-less multiplication product, low part, reversed
|
|
**************************************************************************/
|
|
uint32_t riscv_emulate_clmulr(uint32_t rs1, uint32_t rs2) {
|
|
|
|
uint32_t i;
|
|
uint64_t tmp;
|
|
union {
|
|
uint64_t uint64;
|
|
uint32_t uint32[sizeof(uint64_t)/sizeof(uint32_t)];
|
|
} res;
|
|
|
|
// bit-reversal of input operands
|
|
uint32_t rs1_rev = 0, rs2_rev = 0;
|
|
for (i=0; i<32; i++) {
|
|
rs1_rev <<= 1;
|
|
if ((rs1 >> i) & 1) {
|
|
rs1_rev |= 1;
|
|
}
|
|
rs2_rev <<= 1;
|
|
if ((rs2 >> i) & 1) {
|
|
rs2_rev |= 1;
|
|
}
|
|
}
|
|
|
|
res.uint64 = 0;
|
|
for (i=0; i<32; i++) {
|
|
if ((rs2_rev >> i) & 1) {
|
|
tmp = (uint64_t)rs1_rev;
|
|
tmp = tmp << i;
|
|
res.uint64 = res.uint64 ^ tmp;
|
|
}
|
|
}
|
|
|
|
// bit-reversal of result
|
|
uint32_t result = 0;
|
|
for (i=0; i<32; i++) {
|
|
result <<= 1;
|
|
if ((res.uint32[0] >> i) & 1) {
|
|
result |= 1;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
#endif // neorv32_b_extension_intrinsics_h
|
#endif // neorv32_b_extension_intrinsics_h
|
|
|
No newline at end of file
|
No newline at end of file
|