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:
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
1319
src/arch/riscv/isa/formats/vector_arith.isa
Normal file
1319
src/arch/riscv/isa/formats/vector_arith.isa
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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"
|
||||
|
||||
1989
src/arch/riscv/isa/templates/vector_arith.isa
Normal file
1989
src/arch/riscv/isa/templates/vector_arith.isa
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user