arch-riscv: Add risc-v vector ext v1.0 arith insts support

TODOs:
  + vcompress.vm

Change-Id: I86eceae66e90380416fd3be2c10ad616512b5eba
Co-authored-by: Yang Liu <numbksco@gmail.com>
Co-authored-by: Fan Yang <1209202421@qq.com>
Co-authored-by: Jerin Joy <joy@rivosinc.com>

arch-riscv: Add LICENCE to template files

Change-Id: I825e72bffb84cce559d2e4c1fc2246c3b05a1243
This commit is contained in:
Xuan Hu
2023-02-27 21:31:22 +08:00
committed by Adrià Armejach
parent 91b1d50f59
commit a9f9c4d6d3
10 changed files with 6223 additions and 0 deletions

View File

@@ -122,6 +122,93 @@ VConfOp::generateZimmDisassembly() const
return s.str();
}
std::string
VectorNonSplitInst::generateDisassembly(Addr pc,
const loader::SymbolTable *symtab) const
{
std::stringstream ss;
ss << mnemonic << ' ' << registerName(destRegIdx(0)) << ", "
<< registerName(srcRegIdx(0));
if (machInst.vm == 0) ss << ", v0.t";
return ss.str();
}
std::string VectorArithMicroInst::generateDisassembly(Addr pc,
const loader::SymbolTable *symtab) const
{
std::stringstream ss;
ss << mnemonic << ' ' << registerName(destRegIdx(0)) << ", ";
if (machInst.funct3 == 0x3) {
// OPIVI
ss << registerName(srcRegIdx(0)) << ", " << machInst.vecimm;
} else {
ss << registerName(srcRegIdx(1)) << ", " << registerName(srcRegIdx(0));
}
if (machInst.vm == 0) ss << ", v0.t";
return ss.str();
}
std::string VectorArithMacroInst::generateDisassembly(Addr pc,
const loader::SymbolTable *symtab) const
{
std::stringstream ss;
ss << mnemonic << ' ' << registerName(destRegIdx(0)) << ", ";
if (machInst.funct3 == 0x3) {
// OPIVI
ss << registerName(srcRegIdx(0)) << ", " << machInst.vecimm;
} else {
ss << registerName(srcRegIdx(1)) << ", " << registerName(srcRegIdx(0));
}
if (machInst.vm == 0) ss << ", v0.t";
return ss.str();
}
std::string VectorVMUNARY0MicroInst::generateDisassembly(Addr pc,
const loader::SymbolTable *symtab) const
{
std::stringstream ss;
ss << mnemonic << ' ' << registerName(destRegIdx(0));
if (machInst.vm == 0) ss << ", v0.t";
return ss.str();
}
std::string VectorVMUNARY0MacroInst::generateDisassembly(Addr pc,
const loader::SymbolTable *symtab) const
{
std::stringstream ss;
ss << mnemonic << ' ' << registerName(destRegIdx(0));
if (machInst.vm == 0) ss << ", v0.t";
return ss.str();
}
std::string VectorSlideMicroInst::generateDisassembly(Addr pc,
const loader::SymbolTable *symtab) const
{
std::stringstream ss;
ss << mnemonic << ' ' << registerName(destRegIdx(0)) << ", ";
if (machInst.funct3 == 0x3) {
ss << registerName(srcRegIdx(0)) << ", " << machInst.vecimm;
} else {
ss << registerName(srcRegIdx(1)) << ", " << registerName(srcRegIdx(0));
}
if (machInst.vm == 0) ss << ", v0.t";
return ss.str();
}
std::string VectorSlideMacroInst::generateDisassembly(Addr pc,
const loader::SymbolTable *symtab) const
{
std::stringstream ss;
ss << mnemonic << ' ' << registerName(destRegIdx(0)) << ", ";
if (machInst.funct3 == 0x3) {
ss << registerName(srcRegIdx(0)) << ", " << machInst.vecimm;
} else {
ss << registerName(srcRegIdx(1)) << ", " << registerName(srcRegIdx(0));
}
if (machInst.vm == 0) ss << ", v0.t";
return ss.str();
}
std::string VleMicroInst::generateDisassembly(Addr pc,
const loader::SymbolTable *symtab) const
{
@@ -295,5 +382,25 @@ std::string VsIndexMicroInst::generateDisassembly(Addr pc,
return ss.str();
}
std::string
VMvWholeMacroInst::generateDisassembly(Addr pc,
const loader::SymbolTable *symtab) const
{
std::stringstream ss;
ss << mnemonic << ' ' << registerName(destRegIdx(0)) << ", " <<
registerName(srcRegIdx(1));
return ss.str();
}
std::string
VMvWholeMicroInst::generateDisassembly(Addr pc,
const loader::SymbolTable *symtab) const
{
std::stringstream ss;
ss << mnemonic << ' ' << registerName(destRegIdx(0)) << ", " <<
registerName(srcRegIdx(1));
return ss.str();
}
} // namespace RiscvISA
} // namespace gem5

View File

@@ -89,6 +89,24 @@ inline uint8_t checked_vtype(bool vill, uint8_t vtype) {
return vtype;
}
class VectorNonSplitInst : public RiscvStaticInst
{
protected:
uint32_t vl;
uint8_t vtype;
VectorNonSplitInst(const char* mnem, ExtMachInst _machInst,
OpClass __opClass)
: RiscvStaticInst(mnem, _machInst, __opClass),
vl(_machInst.vl),
vtype(checked_vtype(_machInst.vill, _machInst.vtype8))
{
this->flags[IsVector] = true;
}
std::string generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const override;
};
class VectorMacroInst : public RiscvMacroInst
{
protected:
@@ -170,6 +188,63 @@ class VectorArithMacroInst : public VectorMacroInst
Addr pc, const loader::SymbolTable *symtab) const override;
};
class VectorVMUNARY0MicroInst : public VectorMicroInst
{
protected:
VectorVMUNARY0MicroInst(const char *mnem, ExtMachInst _machInst,
OpClass __opClass, uint8_t _microVl,
uint8_t _microIdx)
: VectorMicroInst(mnem, _machInst, __opClass, _microVl, _microIdx)
{}
std::string generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const override;
};
class VectorVMUNARY0MacroInst : public VectorMacroInst
{
protected:
VectorVMUNARY0MacroInst(const char* mnem, ExtMachInst _machInst,
OpClass __opClass)
: VectorMacroInst(mnem, _machInst, __opClass)
{
this->flags[IsVector] = true;
}
std::string generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const override;
};
class VectorSlideMacroInst : public VectorMacroInst
{
protected:
VectorSlideMacroInst(const char* mnem, ExtMachInst _machInst,
OpClass __opClass)
: VectorMacroInst(mnem, _machInst, __opClass)
{
this->flags[IsVector] = true;
}
std::string generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const override;
};
class VectorSlideMicroInst : public VectorMicroInst
{
protected:
uint8_t vdIdx;
uint8_t vs2Idx;
VectorSlideMicroInst(const char *mnem, ExtMachInst _machInst,
OpClass __opClass, uint8_t _microVl,
uint8_t _microIdx, uint8_t _vdIdx, uint8_t _vs2Idx)
: VectorMicroInst(mnem, _machInst, __opClass, _microVl, _microIdx)
, vdIdx(_vdIdx), vs2Idx(_vs2Idx)
{}
std::string generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const override;
};
class VectorMemMicroInst : public VectorMicroInst
{
protected:
@@ -421,6 +496,131 @@ class VsIndexMicroInst : public VectorMemMicroInst
Addr pc, const loader::SymbolTable *symtab) const override;
};
class VMvWholeMacroInst : public VectorArithMacroInst
{
protected:
VMvWholeMacroInst(const char* mnem, ExtMachInst _machInst,
OpClass __opClass)
: VectorArithMacroInst(mnem, _machInst, __opClass)
{}
std::string generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const override;
};
class VMvWholeMicroInst : public VectorArithMicroInst
{
protected:
VMvWholeMicroInst(const char *mnem, ExtMachInst _machInst,
OpClass __opClass, uint8_t _microVl,
uint8_t _microIdx)
: VectorArithMicroInst(mnem, _machInst, __opClass, _microVl, _microIdx)
{}
std::string generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const override;
};
template<typename ElemType>
class VMaskMergeMicroInst : public VectorArithMicroInst
{
private:
RegId srcRegIdxArr[NumVecInternalRegs];
RegId destRegIdxArr[1];
public:
VMaskMergeMicroInst(ExtMachInst extMachInst, uint8_t _dstReg,
uint8_t _numSrcs)
: VectorArithMicroInst("vmask_mv_micro", extMachInst,
VectorIntegerArithOp, 0, 0)
{
setRegIdxArrays(
reinterpret_cast<RegIdArrayPtr>(
&std::remove_pointer_t<decltype(this)>::srcRegIdxArr),
reinterpret_cast<RegIdArrayPtr>(
&std::remove_pointer_t<decltype(this)>::destRegIdxArr));
_numSrcRegs = 0;
_numDestRegs = 0;
setDestRegIdx(_numDestRegs++, vecRegClass[_dstReg]);
_numTypedDestRegs[VecRegClass]++;
for (uint8_t i=0; i<_numSrcs; i++) {
setSrcRegIdx(_numSrcRegs++, vecRegClass[VecMemInternalReg0 + i]);
}
}
Fault execute(ExecContext* xc, trace::InstRecord* traceData)
const override {
vreg_t tmp_d0 = *(vreg_t *)xc->getWritableRegOperand(this, 0);
auto Vd = tmp_d0.as<uint8_t>();
constexpr uint8_t elems_per_vreg = VLENB / sizeof(ElemType);
size_t bit_cnt = elems_per_vreg;
vreg_t tmp_s;
xc->getRegOperand(this, 0, &tmp_s);
auto s = tmp_s.as<uint8_t>();
// cp the first result and tail
memcpy(Vd, s, VLENB);
for (uint8_t i = 1; i < this->_numSrcRegs; i++) {
xc->getRegOperand(this, i, &tmp_s);
s = tmp_s.as<uint8_t>();
if constexpr (elems_per_vreg < 8) {
constexpr uint8_t m = (1 << elems_per_vreg) - 1;
const uint8_t mask = m << (i * elems_per_vreg % 8);
// clr & ext bits
Vd[bit_cnt/8] ^= Vd[bit_cnt/8] & mask;
Vd[bit_cnt/8] |= s[bit_cnt/8] & mask;
bit_cnt += elems_per_vreg;
} else {
constexpr uint8_t byte_offset = elems_per_vreg / 8;
memcpy(Vd + i * byte_offset, s + i * byte_offset, byte_offset);
}
}
xc->setRegOperand(this, 0, &tmp_d0);
if (traceData)
traceData->setData(vecRegClass, &tmp_d0);
return NoFault;
}
std::string generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const override {
std::stringstream ss;
ss << mnemonic << ' ' << registerName(destRegIdx(0));
for (uint8_t i = 0; i < this->_numSrcRegs; i++) {
ss << ", " << registerName(srcRegIdx(i));
}
ss << ", offset:" << VLENB / sizeof(ElemType);
return ss.str();
}
};
class VxsatMicroInst : public VectorArithMicroInst
{
private:
bool* vxsat;
public:
VxsatMicroInst(bool* Vxsat, ExtMachInst extMachInst)
: VectorArithMicroInst("vxsat_micro", extMachInst,
VectorIntegerArithOp, 0, 0)
{
vxsat = Vxsat;
}
Fault execute(ExecContext* xc, trace::InstRecord* traceData)
const override
{
xc->setMiscReg(MISCREG_VXSAT,*vxsat);
auto vcsr = xc->readMiscReg(MISCREG_VCSR);
xc->setMiscReg(MISCREG_VCSR, ((vcsr&~1)|*vxsat));
return NoFault;
}
std::string generateDisassembly(Addr pc, const loader::SymbolTable *symtab)
const override
{
std::stringstream ss;
ss << mnemonic << ' ' << "VXSAT" << ", " << (*vxsat ? "0x1" : "0x0");
return ss.str();
}
};
} // namespace RiscvISA
} // namespace gem5

File diff suppressed because it is too large Load Diff

View File

@@ -38,6 +38,7 @@
##include "amo.isa"
##include "bs.isa"
##include "vector_conf.isa"
##include "vector_arith.isa"
##include "vector_mem.isa"
// Include formats for nonstandard extensions

File diff suppressed because it is too large Load Diff

View File

@@ -1,2 +1,32 @@
// -*- mode:c++ -*-
// Copyright (c) 2022 PLCT Lab
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// 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;
// neither the name of the copyright holders 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
// OWNER 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.
// Include
##include "vector_mem.isa"
##include "vector_arith.isa"

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,31 @@
// -*- mode:c++ -*-
// Copyright (c) 2022 PLCT Lab
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// 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;
// neither the name of the copyright holders 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
// OWNER 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.
def template VMemMacroDeclare {{
class %(class_name)s : public %(base_class)s

View File

@@ -211,6 +211,20 @@ const std::vector<std::string> RegNames = {
} // namespace float_reg
inline float32_t
fsgnj32(float32_t a, float32_t b, bool n, bool x) {
if (n) b.v = ~b.v;
else if (x) b.v = a.v ^ b.v;
return f32(insertBits(b.v, 30, 0, a.v));
}
inline float64_t
fsgnj64(float64_t a, float64_t b, bool n, bool x) {
if (n) b.v = ~b.v;
else if (x) b.v = a.v ^ b.v;
return f64(insertBits(b.v, 62, 0, a.v));
}
} // namespace RiscvISA
} // namespace gem5

View File

@@ -241,6 +241,13 @@ remu(T rs1, T rs2)
return (rs2 == 0) ? rs1 : rs1 % rs2;
}
// Vector extension functions
inline uint64_t
vtype_SEW(const uint64_t vtype)
{
return 8 << bits(vtype, 5, 3);
}
/*
* Encode LMUL to lmul as follows:
* LMUL vlmul lmul
@@ -269,6 +276,25 @@ vtype_VLMAX(const uint64_t vtype, const bool per_reg = false)
return gem5::RiscvISA::VLEN >> (vsew + 3 - lmul);
}
inline int64_t
vtype_vlmul(const uint64_t vtype)
{
return (int64_t)sext<3>(bits(vtype, 2, 0));
}
inline uint64_t
vtype_regs_per_group(const uint64_t vtype)
{
int64_t lmul = (int64_t)sext<3>(bits(vtype, 2, 0));
return 1 << std::max<int64_t>(0, lmul);
}
inline void
vtype_set_vill(uint64_t& vtype)
{
vtype = (uint64_t)0 ^ (1UL << (sizeof(RegVal) * 8 - 1));
}
inline uint64_t
width_EEW(uint64_t width)
{
@@ -296,6 +322,461 @@ elem_mask(const T* vs, const int index)
return (vs[idx] >> pos) & 1;
}
template<typename Type> struct double_width;
template<> struct double_width<uint8_t> { using type = uint16_t;};
template<> struct double_width<uint16_t> { using type = uint32_t;};
template<> struct double_width<uint32_t> { using type = uint64_t;};
template<> struct double_width<int8_t> { using type = int16_t; };
template<> struct double_width<int16_t> { using type = int32_t; };
template<> struct double_width<int32_t> { using type = int64_t; };
template<> struct double_width<float32_t> { using type = float64_t;};
template<typename Type> struct double_widthf;
template<> struct double_widthf<uint32_t> { using type = float64_t;};
template<> struct double_widthf<int32_t> { using type = float64_t;};
template<typename FloatType, typename IntType = decltype(FloatType::v)> auto
ftype(IntType a) -> FloatType
{
if constexpr(std::is_same_v<uint32_t, IntType>)
return f32(a);
else if constexpr(std::is_same_v<uint64_t, IntType>)
return f64(a);
GEM5_UNREACHABLE;
}
// TODO: Consolidate ftype_freg(freg_t a) and ftype(IntType a) into a
// single function
template<typename FloatType, typename IntType = decltype(FloatType::v)> auto
ftype_freg(freg_t a) -> FloatType
{
if constexpr(std::is_same_v<uint32_t, IntType>)
return f32(a);
else if constexpr(std::is_same_v<uint64_t, IntType>)
return f64(a);
GEM5_UNREACHABLE;
}
template<typename FloatType> FloatType
fadd(FloatType a, FloatType b)
{
if constexpr(std::is_same_v<float32_t, FloatType>)
return f32_add(a, b);
else if constexpr(std::is_same_v<float64_t, FloatType>)
return f64_add(a, b);
GEM5_UNREACHABLE;
}
template<typename FloatType> FloatType
fsub(FloatType a, FloatType b)
{
if constexpr(std::is_same_v<float32_t, FloatType>)
return f32_sub(a, b);
else if constexpr(std::is_same_v<float64_t, FloatType>)
return f64_sub(a, b);
GEM5_UNREACHABLE;
}
template<typename FloatType> FloatType
fmin(FloatType a, FloatType b)
{
if constexpr(std::is_same_v<float32_t, FloatType>)
return f32_min(a, b);
else if constexpr(std::is_same_v<float64_t, FloatType>)
return f64_min(a, b);
GEM5_UNREACHABLE;
}
template<typename FloatType> FloatType
fmax(FloatType a, FloatType b)
{
if constexpr(std::is_same_v<float32_t, FloatType>)
return f32_max(a, b);
else if constexpr(std::is_same_v<float64_t, FloatType>)
return f64_max(a, b);
GEM5_UNREACHABLE;
}
template<typename FloatType> FloatType
fdiv(FloatType a, FloatType b)
{
if constexpr(std::is_same_v<float32_t, FloatType>)
return f32_div(a, b);
else if constexpr(std::is_same_v<float64_t, FloatType>)
return f64_div(a, b);
GEM5_UNREACHABLE;
}
template<typename FloatType> FloatType
fmul(FloatType a, FloatType b)
{
if constexpr(std::is_same_v<float32_t, FloatType>)
return f32_mul(a, b);
else if constexpr(std::is_same_v<float64_t, FloatType>)
return f64_mul(a, b);
GEM5_UNREACHABLE;
}
template<typename FloatType> FloatType
fsqrt(FloatType a)
{
if constexpr(std::is_same_v<float32_t, FloatType>)
return f32_sqrt(a);
else if constexpr(std::is_same_v<float64_t, FloatType>)
return f64_sqrt(a);
GEM5_UNREACHABLE;
}
template<typename FloatType> FloatType
frsqrte7(FloatType a)
{
if constexpr(std::is_same_v<float32_t, FloatType>)
return f32_rsqrte7(a);
else if constexpr(std::is_same_v<float64_t, FloatType>)
return f64_rsqrte7(a);
GEM5_UNREACHABLE;
}
template<typename FloatType> FloatType
frecip7(FloatType a)
{
if constexpr(std::is_same_v<float32_t, FloatType>)
return f32_recip7(a);
else if constexpr(std::is_same_v<float64_t, FloatType>)
return f64_recip7(a);
GEM5_UNREACHABLE;
}
template<typename FloatType> FloatType
fclassify(FloatType a)
{
if constexpr(std::is_same_v<float32_t, FloatType>)
return f32(f32_classify(a));
else if constexpr(std::is_same_v<float64_t, FloatType>)
return f64(f64_classify(a));
GEM5_UNREACHABLE;
}
template<typename FloatType> FloatType
fsgnj(FloatType a, FloatType b, bool n, bool x)
{
if constexpr(std::is_same_v<float32_t, FloatType>)
return fsgnj32(a, b, n, x);
else if constexpr(std::is_same_v<float64_t, FloatType>)
return fsgnj64(a, b, n, x);
GEM5_UNREACHABLE;
}
template<typename FloatType> bool
fle(FloatType a, FloatType b)
{
if constexpr(std::is_same_v<float32_t, FloatType>)
return f32_le(a, b);
else if constexpr(std::is_same_v<float64_t, FloatType>)
return f64_le(a, b);
GEM5_UNREACHABLE;
}
template<typename FloatType> bool
feq(FloatType a, FloatType b)
{
if constexpr(std::is_same_v<float32_t, FloatType>)
return f32_eq(a, b);
else if constexpr(std::is_same_v<float64_t, FloatType>)
return f64_eq(a, b);
GEM5_UNREACHABLE;
}
template<typename FloatType> bool
flt(FloatType a, FloatType b)
{
if constexpr(std::is_same_v<float32_t, FloatType>)
return f32_lt(a, b);
else if constexpr(std::is_same_v<float64_t, FloatType>)
return f64_lt(a, b);
GEM5_UNREACHABLE;
}
template<typename FloatType> FloatType
fmadd(FloatType a, FloatType b, FloatType c)
{
if constexpr(std::is_same_v<float32_t, FloatType>)
return f32_mulAdd(a, b, c);
else if constexpr(std::is_same_v<float64_t, FloatType>)
return f64_mulAdd(a, b, c);
GEM5_UNREACHABLE;
}
template<typename FloatType> FloatType
fneg(FloatType a)
{
if constexpr(std::is_same_v<float32_t, FloatType>)
return f32(a.v ^ uint32_t(mask(31, 31)));
else if constexpr(std::is_same_v<float64_t, FloatType>)
return f64(a.v ^ mask(63, 63));
GEM5_UNREACHABLE;
}
template<typename FT, typename WFT = typename double_width<FT>::type> WFT
fwiden(FT a)
{
if constexpr(std::is_same_v<float32_t, FT>)
return f32_to_f64(a);
GEM5_UNREACHABLE;
}
template<typename FloatType, typename IntType = decltype(FloatType::v)> IntType
f_to_ui(FloatType a, uint_fast8_t mode)
{
if constexpr(std::is_same_v<float32_t, FloatType>)
return f32_to_ui32(a, mode, true);
else if constexpr(std::is_same_v<float64_t, FloatType>)
return f64_to_ui64(a, mode, true);
GEM5_UNREACHABLE;
}
template<
typename FloatType,
typename IntType = decltype(double_width<FloatType>::type::v)
> IntType
f_to_wui(FloatType a, uint_fast8_t mode)
{
if constexpr(std::is_same_v<float32_t, FloatType>)
return f32_to_ui64(a, mode, true);
GEM5_UNREACHABLE;
}
template<
typename IntType,
typename FloatType = typename double_widthf<IntType>::type
> IntType
f_to_nui(FloatType a, uint_fast8_t mode)
{
if constexpr(std::is_same_v<float64_t, FloatType>)
return f64_to_ui32(a, mode, true);
GEM5_UNREACHABLE;
}
template<typename FloatType, typename IntType = decltype(FloatType::v)> IntType
f_to_i(FloatType a, uint_fast8_t mode)
{
if constexpr(std::is_same_v<float32_t, FloatType>)
return (uint32_t)f32_to_i32(a, mode, true);
else if constexpr(std::is_same_v<float64_t, FloatType>)
return (uint64_t)f64_to_i64(a, mode, true);
GEM5_UNREACHABLE;
}
template<
typename FloatType,
typename IntType = decltype(double_width<FloatType>::type::v)
> IntType
f_to_wi(FloatType a, uint_fast8_t mode)
{
if constexpr(std::is_same_v<float32_t, FloatType>)
return (uint64_t)f32_to_i64(a, mode, true);
GEM5_UNREACHABLE;
}
template<
typename IntType,
typename FloatType = typename double_widthf<IntType>::type
> IntType
f_to_ni(FloatType a, uint_fast8_t mode)
{
if constexpr(std::is_same_v<float64_t, FloatType>)
return (uint32_t)f64_to_i32(a, mode, true);
GEM5_UNREACHABLE;
}
template<typename FloatType, typename IntType = decltype(FloatType::v)>
FloatType
ui_to_f(IntType a)
{
if constexpr(std::is_same_v<float32_t, FloatType>)
return ui32_to_f32(a);
else if constexpr(std::is_same_v<float64_t, FloatType>)
return ui64_to_f64(a);
GEM5_UNREACHABLE;
}
template<
typename IntType,
typename FloatType = typename double_widthf<IntType>::type
> FloatType
ui_to_wf(IntType a)
{
if constexpr(std::is_same_v<float64_t, FloatType>)
return ui32_to_f64(a);
GEM5_UNREACHABLE;
}
template<
typename FloatType,
typename IntType = decltype(double_width<FloatType>::type::v)
> FloatType
ui_to_nf(IntType a)
{
if constexpr(std::is_same_v<float32_t, FloatType>)
return ui64_to_f32(a);
GEM5_UNREACHABLE;
}
template<typename FloatType, typename IntType = decltype(FloatType::v)>
FloatType
i_to_f(IntType a)
{
if constexpr(std::is_same_v<float32_t, FloatType>)
return i32_to_f32((int32_t)a);
else if constexpr(std::is_same_v<float64_t, FloatType>)
return i64_to_f64((int64_t)a);
GEM5_UNREACHABLE;
}
template<
typename IntType,
typename FloatType = typename double_widthf<IntType>::type
> FloatType
i_to_wf(IntType a)
{
if constexpr(std::is_same_v<float64_t, FloatType>)
return i32_to_f64((int32_t)a);
GEM5_UNREACHABLE;
}
template<
typename FloatType,
typename IntType = std::make_signed_t<
decltype(double_width<FloatType>::type::v)
>
> FloatType
i_to_nf(IntType a)
{
if constexpr(std::is_same_v<float32_t, FloatType>)
return i64_to_f32(a);
GEM5_UNREACHABLE;
}
template<
typename FloatType,
typename FloatWType = typename double_width<FloatType>::type
> FloatWType
f_to_wf(FloatType a)
{
if constexpr(std::is_same_v<float32_t, FloatType>)
return f32_to_f64(a);
GEM5_UNREACHABLE;
}
template<
typename FloatNType,
typename FloatType = typename double_width<FloatNType>::type
> FloatNType
f_to_nf(FloatType a)
{
if constexpr(std::is_same_v<float64_t, FloatType>)
return f64_to_f32(a);
GEM5_UNREACHABLE;
}
//ref: https://locklessinc.com/articles/sat_arithmetic/
template<typename T> T
sat_add(T x, T y, bool* sat)
{
using UT = std::make_unsigned_t<T>;
UT ux = x;
UT uy = y;
UT res = ux + uy;
int sh = sizeof(T) * 8 - 1;
ux = (ux >> sh) + (((UT)0x1 << sh) - 1);
if ((T) ((ux ^ uy) | ~(uy ^ res)) >= 0) {
res = ux;
*sat = true;
}
return res;
}
template<typename T> T
sat_sub(T x, T y, bool* sat)
{
using UT = std::make_unsigned_t<T>;
UT ux = x;
UT uy = y;
UT res = ux - uy;
int sh = sizeof(T) * 8 - 1;
ux = (ux >> sh) + (((UT)0x1 << sh) - 1);
if ((T) ((ux ^ uy) & (ux ^ res)) < 0) {
res = ux;
*sat = true;
}
return res;
}
template<typename T> T
sat_addu(T x, T y, bool* sat)
{
T res = x + y;
bool t = res < x;
if (false == *sat){
*sat = t;
}
res |= -(res < x);
return res;
}
template<typename T> T
sat_subu(T x, T y, bool* sat)
{
T res = x - y;
bool t = !(res <= x);
if (false == *sat){
*sat = t;
}
res &= -(res <= x);
return res;
}
/**
* Ref:
* https://github.com/riscv-software-src/riscv-isa-sim
*/
template<typename T> T
int_rounding(T result, uint8_t xrm, unsigned gb) {
const uint64_t lsb = 1UL << gb;
const uint64_t lsb_half = lsb >> 1;
switch (xrm) {
case 0 /* RNU */:
result += lsb_half;
break;
case 1 /* RNE */:
if ((result & lsb_half) &&
((result & (lsb_half - 1)) || (result & lsb)))
result += lsb;
break;
case 2 /* RDN */:
break;
case 3 /* ROD */:
if (result & (lsb - 1))
result |= lsb;
break;
default:
panic("Invalid xrm value %d", (int)xrm);
}
return result;
}
} // namespace RiscvISA
} // namespace gem5