OpenCores
URL https://opencores.org/ocsvn/neorv32/neorv32/trunk

Subversion Repositories neorv32

[/] [neorv32/] [trunk/] [sw/] [example/] [bitmanip_test/] [neorv32_b_extension_intrinsics.h] - Rev 71

Compare with Previous | Blame | View Log

// #################################################################################################
// # << 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) 2022, 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.
 * @return Number of leading zeros in source operand.
 **************************************************************************/
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_clz(uint32_t rs1) {
 
  return CUSTOM_INSTR_R1_TYPE(0b0110000, 0b00000, rs1, 0b001, 0b0010011);
}
 
 
/**********************************************************************//**
 * Intrinsic: Bit manipulation CTZ (count trailing zeros) [B.Zbb]
 *
 * @param[in] rs1 Source operand 1.
 * @return Number of trailing zeros in source operand.
 **************************************************************************/
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_ctz(uint32_t rs1) {
 
  return CUSTOM_INSTR_R1_TYPE(0b0110000, 0b00001, rs1, 0b001, 0b0010011);
}
 
 
/**********************************************************************//**
 * Intrinsic: Bit manipulation CPOP (count set bits) [B.Zbb]
 *
 * @param[in] rs1 Source operand 1.
 * @return Number of set bits in source operand.
 **************************************************************************/
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_cpop(uint32_t rs1) {
 
  return CUSTOM_INSTR_R1_TYPE(0b0110000, 0b00010, rs1, 0b001, 0b0010011);
}
 
 
/**********************************************************************//**
 * Intrinsic: Bit manipulation SEXT.B (sign-extend byte) [B.Zbb]
 *
 * @param[in] rs1 Source operand 1.
 * @return Sign extended byte (operand(7:0)).
 **************************************************************************/
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_sextb(uint32_t rs1) {
 
  return CUSTOM_INSTR_R1_TYPE(0b0110000, 0b00100, rs1, 0b001, 0b0010011);
}
 
 
/**********************************************************************//**
 * Intrinsic: Bit manipulation SEXT.H (sign-extend half-word) [B.Zbb]
 *
 * @param[in] rs1 Source operand 1.
 * @return Sign-extended half-word (operand(15:0)).
 **************************************************************************/
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_sexth(uint32_t rs1) {
 
  return CUSTOM_INSTR_R1_TYPE(0b0110000, 0b00101, rs1, 0b001, 0b0010011);
}
 
 
/**********************************************************************//**
 * Intrinsic: Bit manipulation ZEXT.H (zero-extend half-word) [B.Zbb]
 *
 * @param[in] rs1 Source operand 1.
 * @return Zero-extended half-word (operand(15:0)).
 **************************************************************************/
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_zexth(uint32_t rs1) {
 
  return CUSTOM_INSTR_R1_TYPE(0b0000100, 0b00000, rs1, 0b100, 0b0110011);
}
 
 
/**********************************************************************//**
 * Intrinsic: Bit manipulation MIN (select signed minimum) [B.Zbb]
 *
 * @param[in] rs1 Source operand 1.
 * @param[in] rs2 Source operand 2.
 * @return Signed minimum.
 **************************************************************************/
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_min(uint32_t rs1, uint32_t rs2) {
 
  return CUSTOM_INSTR_R2_TYPE(0b0000101, rs2, rs1, 0b100, 0b0110011);
}
 
 
/**********************************************************************//**
 * Intrinsic: Bit manipulation MINU (select unsigned minimum) [B.Zbb]
 *
 * @param[in] rs1 Source operand 1.
 * @param[in] rs2 Source operand 2.
 * @return Unsigned minimum.
 **************************************************************************/
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_minu(uint32_t rs1, uint32_t rs2) {
 
  return CUSTOM_INSTR_R2_TYPE(0b0000101, rs2, rs1, 0b101, 0b0110011);
}
 
 
/**********************************************************************//**
 * Intrinsic: Bit manipulation MAX (select signed maximum) [B.Zbb]
 *
 * @param[in] rs1 Source operand 1.
 * @param[in] rs2 Source operand 2.
 * @return Signed maximum.
 **************************************************************************/
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_max(uint32_t rs1, uint32_t rs2) {
 
  return CUSTOM_INSTR_R2_TYPE(0b0000101, rs2, rs1, 0b110, 0b0110011);
}
 
 
/**********************************************************************//**
 * Intrinsic: Bit manipulation MAXU (select unsigned maximum) [B.Zbb]
 *
 * @param[in] rs1 Source operand 1.
 * @param[in] rs2 Source operand 2.
 * @return Unsigned maximum.
 **************************************************************************/
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_maxu(uint32_t rs1, uint32_t rs2) {
 
  return CUSTOM_INSTR_R2_TYPE(0b0000101, rs2, rs1, 0b111, 0b0110011);
}
 
 
/**********************************************************************//**
 * Intrinsic: Bit manipulation ANDN (logical and-negate) [B.Zbb]
 *
 * @param[in] rs1 Source operand 1.
 * @param[in] rs2 Source 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) {
 
  return CUSTOM_INSTR_R2_TYPE(0b0100000, rs2, rs1, 0b111, 0b0110011);
}
 
 
/**********************************************************************//**
 * Intrinsic: Bit manipulation ORN (logical or-negate) [B.Zbb]
 *
 * @param[in] rs1 Source operand 1.
 * @param[in] rs2 Source operand 2.
 * @return Operand 1 OR NOT operand 2.
 **************************************************************************/
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_orn(uint32_t rs1, uint32_t rs2) {
 
  return CUSTOM_INSTR_R2_TYPE(0b0100000, rs2, rs1, 0b110, 0b0110011);
}
 
 
/**********************************************************************//**
 * Intrinsic: Bit manipulation XNOR (logical xor-negate) [B.Zbb]
 *
 * @param[in] rs1 Source operand 1.
 * @param[in] rs2 Source operand 2.
 * @return Operand 1 XOR NOT operand 2.
 **************************************************************************/
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_xnor(uint32_t rs1, uint32_t rs2) {
 
  return CUSTOM_INSTR_R2_TYPE(0b0100000, rs2, rs1, 0b100, 0b0110011);
}
 
 
/**********************************************************************//**
 * Intrinsic: Bit manipulation ROL (rotate-left) [B.Zbb]
 *
 * @param[in] rs1 Source operand 1.
 * @param[in] rs2 Source operand 2.
 * @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) {
 
  return CUSTOM_INSTR_R2_TYPE(0b0110000, rs2, rs1, 0b001, 0b0110011);
}
 
 
/**********************************************************************//**
 * Intrinsic: Bit manipulation ROR (rotate-right) [B.Zbb]
 *
 * @param[in] rs1 Source operand 1.
 * @param[in] rs2 Source operand 2.
 * @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) {
 
  return CUSTOM_INSTR_R2_TYPE(0b0110000, rs2, rs1, 0b101, 0b0110011);
}
 
 
/**********************************************************************//**
 * Intrinsic: Bit manipulation RORI (rotate-right) by 20 positions. [B.Zbb]
 * @warning Fixed shift amount (20) for now.
 *
 * @param[in] rs1 Source operand 1.
 * @return Operand 1 rotated right by 20 positions.
 **************************************************************************/
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_rori20(uint32_t rs1) {
 
  return CUSTOM_INSTR_R1_TYPE(0b0110000, 0b10100, rs1, 0b101, 0b0010011);
}
 
 
/**********************************************************************//**
 * Intrinsic: Bit manipulation ORC.B (or-combine byte) [B.Zbb]
 *
 * @param[in] rs1 Source operand 1.
 * @return OR-combined bytes of operand 1.
 **************************************************************************/
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_orcb(uint32_t rs1) {
 
  return CUSTOM_INSTR_R1_TYPE(0b0010100, 0b00111, rs1, 0b101, 0b0010011);
}
 
 
/**********************************************************************//**
 * Intrinsic: Bit manipulation REV8 (byte-swap) [B.Zbb]
 *
 * @param[in] rs1 Source operand 1.
 * @return Byte swap of operand 1
 **************************************************************************/
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_rev8(uint32_t rs1) {
 
  return CUSTOM_INSTR_R1_TYPE(0b0110100, 0b11000, rs1, 0b101, 0b0010011);
}
 
 
// ================================================================================================
// Zba - Address-generation instructions
// ================================================================================================
 
/**********************************************************************//**
 * Intrinsic: Address generation instructions SH1ADD (add with logical-1-shift) [B.Zba]
 *
 * @param[in] rs1 Source operand 1.
 * @param[in] rs2 Source operand 2.
 * @return Operand 2 + (Operand 1 << 1)
 **************************************************************************/
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_sh1add(uint32_t rs1, uint32_t rs2) {
 
  return CUSTOM_INSTR_R2_TYPE(0b0010000, rs2, rs1, 0b010, 0b0110011);
}
 
 
/**********************************************************************//**
 * Intrinsic: Address generation instructions SH2ADD (add with logical-2-shift) [B.Zba]
 *
 * @param[in] rs1 Source operand 1.
 * @param[in] rs2 Source operand 2.
 * @return Operand 2 + (Operand 1 << 2)
 **************************************************************************/
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_sh2add(uint32_t rs1, uint32_t rs2) {
 
  return CUSTOM_INSTR_R2_TYPE(0b0010000, rs2, rs1, 0b100, 0b0110011);
}
 
/**********************************************************************//**
 * Intrinsic: Address generation instructions SH1ADD (add with logical-3-shift) [B.Zba]
 *
 * @param[in] rs1 Source operand 1.
 * @param[in] rs2 Source operand 2.
 * @return Operand 2 + (Operand 1 << 3)
 **************************************************************************/
inline uint32_t __attribute__ ((always_inline)) riscv_intrinsic_sh3add(uint32_t rs1, uint32_t rs2) {
 
  return CUSTOM_INSTR_R2_TYPE(0b0010000, rs2, rs1, 0b110, 0b0110011);
}
 
 
// ================================================================================================
// Zbs - Single-bit instructions
// ================================================================================================
 
 
/**********************************************************************//**
 * 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
// ################################################################################################
 
 
// ================================================================================================
// Zbb - Base instructions
// ================================================================================================
 
 
/**********************************************************************//**
 * Intrinsic: Bit manipulation CLZ (count leading zeros) [emulation]
 *
 * @param[in] rs1 Source operand 1.
 * @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.
 * @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.
 * @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.
 * @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.
 * @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.
 * @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.
 * @param[in] rs2 Source operand 1.
 * @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.
 * @param[in] rs2 Source operand 1.
 * @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.
 * @param[in] rs2 Source operand 1.
 * @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.
 * @param[in] rs2 Source operand 1.
 * @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.
 * @param[in] rs2 Source operand 1.
 * @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.
 * @param[in] rs2 Source operand 1.
 * @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.
 * @param[in] rs2 Source operand 1.
 * @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.
 * @param[in] rs2 Source operand 1.
 * @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.
 * @param[in] rs2 Source operand 1.
 * @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.
 * @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.
 * @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.
 * @param[in] rs2 Source operand 1.
 * @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.
 * @param[in] rs2 Source operand 1.
 * @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.
 * @param[in] rs2 Source operand 1.
 * @return Operand 2 + (Operand 1 << 3)
 **************************************************************************/
uint32_t riscv_emulate_sh3add(uint32_t rs1, uint32_t rs2) {
 
  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
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

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