Merge branch 'develop' into riscv-fix-style

This commit is contained in:
Harshil Patel
2023-08-03 13:32:53 -07:00
committed by GitHub
30 changed files with 9326 additions and 21 deletions

View File

@@ -90,7 +90,7 @@ board = SimpleBoard(
board.set_se_binary_workload(
# the workload should be the same as the save-checkpoint script
obtain_resource("riscv-hello"),
checkpoint=obtain_resource("riscv-hello-example-checkpoint-v23"),
checkpoint=obtain_resource("riscv-hello-example-checkpoint"),
)
simulator = Simulator(

View File

@@ -41,6 +41,17 @@ class RiscvCPU:
ArchISA = RiscvISA
class RiscvISANoRVV(RiscvISA):
enable_rvv = False
class RiscvCPUNoRVV:
ArchDecoder = RiscvDecoder
ArchMMU = RiscvMMU
ArchInterrupts = RiscvInterrupts
ArchISA = RiscvISANoRVV
class RiscvAtomicSimpleCPU(BaseAtomicSimpleCPU, RiscvCPU):
mmu = RiscvMMU()
@@ -53,9 +64,9 @@ class RiscvTimingSimpleCPU(BaseTimingSimpleCPU, RiscvCPU):
mmu = RiscvMMU()
class RiscvO3CPU(BaseO3CPU, RiscvCPU):
class RiscvO3CPU(BaseO3CPU, RiscvCPUNoRVV):
mmu = RiscvMMU()
class RiscvMinorCPU(BaseMinorCPU, RiscvCPU):
class RiscvMinorCPU(BaseMinorCPU, RiscvCPUNoRVV):
mmu = RiscvMMU()

View File

@@ -24,6 +24,7 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from m5.objects.InstDecoder import InstDecoder
from m5.params import *
class RiscvDecoder(InstDecoder):

View File

@@ -56,3 +56,5 @@ class RiscvISA(BaseISA):
True, "whether to check memory access alignment"
)
riscv_type = Param.RiscvType("RV64", "RV32 or RV64")
enable_rvv = Param.Bool(True, "Enable vector extension")

View File

@@ -28,6 +28,7 @@
*/
#include "arch/riscv/decoder.hh"
#include "arch/riscv/isa.hh"
#include "arch/riscv/types.hh"
#include "base/bitfield.hh"
#include "debug/Decode.hh"
@@ -38,10 +39,18 @@ namespace gem5
namespace RiscvISA
{
Decoder::Decoder(const RiscvDecoderParams &p) : InstDecoder(p, &machInst)
{
ISA *isa = dynamic_cast<ISA*>(p.isa);
enableRvv = isa->getEnableRvv();
reset();
}
void Decoder::reset()
{
aligned = true;
mid = false;
vConfigDone = true;
machInst = 0;
emi = 0;
}
@@ -49,6 +58,19 @@ void Decoder::reset()
void
Decoder::moreBytes(const PCStateBase &pc, Addr fetchPC)
{
// TODO: Current vsetvl instructions stall decode. Future fixes should
// enable speculation, and this code will be removed.
if (GEM5_UNLIKELY(!this->vConfigDone)) {
fatal_if(!enableRvv,
"Vector extension is not enabled for this CPU type\n"
"You can manually enable vector extensions by setting rvv_enabled "
"to true for each ISA object after `createThreads()`\n");
DPRINTF(Decode, "Waiting for vset*vl* to be executed\n");
instDone = false;
outOfBytes = false;
return;
}
// The MSB of the upper and lower halves of a machine instruction.
constexpr size_t max_bit = sizeof(machInst) * 8 - 1;
constexpr size_t mid_bit = sizeof(machInst) * 4 - 1;
@@ -78,6 +100,14 @@ Decoder::moreBytes(const PCStateBase &pc, Addr fetchPC)
instDone = compressed(emi);
}
}
if (instDone) {
emi.vl = this->machVl;
emi.vtype8 = this->machVtype & 0xff;
emi.vill = this->machVtype.vill;
if (vconf(emi)) {
this->vConfigDone = false; // set true when vconfig inst execute
}
}
}
StaticInstPtr
@@ -116,5 +146,14 @@ Decoder::decode(PCStateBase &_next_pc)
return decode(emi, next_pc.instAddr());
}
void
Decoder::setVlAndVtype(uint32_t vl, VTYPE vtype)
{
this->machVtype = vtype;
this->machVl = vl;
this->vConfigDone = true;
}
} // namespace RiscvISA
} // namespace gem5

View File

@@ -32,6 +32,7 @@
#include "arch/generic/decode_cache.hh"
#include "arch/generic/decoder.hh"
#include "arch/riscv/insts/vector.hh"
#include "arch/riscv/types.hh"
#include "base/logging.hh"
#include "base/types.hh"
@@ -53,12 +54,17 @@ class Decoder : public InstDecoder
decode_cache::InstMap<ExtMachInst> instMap;
bool aligned;
bool mid;
bool vConfigDone;
protected:
//The extended machine instruction being generated
ExtMachInst emi;
uint32_t machInst;
bool enableRvv = false;
VTYPE machVtype;
uint32_t machVl;
StaticInstPtr decodeInst(ExtMachInst mach_inst);
/// Decode a machine instruction.
@@ -67,20 +73,22 @@ class Decoder : public InstDecoder
StaticInstPtr decode(ExtMachInst mach_inst, Addr addr);
public:
Decoder(const RiscvDecoderParams &p) : InstDecoder(p, &machInst)
{
reset();
}
Decoder(const RiscvDecoderParams &p);
void reset() override;
inline bool compressed(ExtMachInst inst) { return (inst & 0x3) < 0x3; }
inline bool compressed(ExtMachInst inst) { return inst.quadRant < 0x3; }
inline bool vconf(ExtMachInst inst) {
return inst.opcode == 0b1010111u && inst.funct3 == 0b111u;
}
//Use this to give data to the decoder. This should be used
//when there is control flow.
void moreBytes(const PCStateBase &pc, Addr fetchPC) override;
StaticInstPtr decode(PCStateBase &nextPC) override;
void setVlAndVtype(uint32_t vl, VTYPE vtype);
};
} // namespace RiscvISA

View File

@@ -173,7 +173,7 @@ class InstFault : public RiscvFault
: RiscvFault(n, FaultType::OTHERS, INST_ILLEGAL), _inst(inst)
{}
RegVal trap_value() const override { return bits(_inst, 31, 0); }
RegVal trap_value() const override { return _inst.instBits; }
};
class UnknownInstFault : public InstFault

View File

@@ -33,3 +33,4 @@ Source('compressed.cc', tags='riscv isa')
Source('mem.cc', tags='riscv isa')
Source('standard.cc', tags='riscv isa')
Source('static_inst.cc', tags='riscv isa')
Source('vector.cc', tags='riscv isa')

View File

@@ -33,6 +33,7 @@
#include <string>
#include "arch/riscv/pcstate.hh"
#include "arch/riscv/regs/misc.hh"
#include "arch/riscv/types.hh"
#include "cpu/exec_context.hh"
#include "cpu/static_inst.hh"

View File

@@ -0,0 +1,408 @@
/*
* 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 "arch/riscv/insts/vector.hh"
#include <sstream>
#include <string>
#include "arch/riscv/insts/static_inst.hh"
#include "arch/riscv/utility.hh"
#include "cpu/static_inst.hh"
namespace gem5
{
namespace RiscvISA
{
/**
* This function translates the 3-bit value of vlmul bits to the corresponding
* lmul value as specified in RVV 1.0 spec p11-12 chapter 3.4.2.
*
* I.e.,
* vlmul = -3 -> LMUL = 1/8
* vlmul = -2 -> LMUL = 1/4
* vlmul = -1 -> LMUL = 1/2
* vlmul = 0 -> LMUL = 1
* vlmul = 1 -> LMUL = 2
* vlmul = 2 -> LMUL = 4
* vlmul = 3 -> LMUL = 8
*
**/
float
getVflmul(uint32_t vlmul_encoding)
{
int vlmul = sext<3>(vlmul_encoding & 7);
float vflmul = vlmul >= 0 ? 1 << vlmul : 1.0 / (1 << -vlmul);
return vflmul;
}
uint32_t
getVlmax(VTYPE vtype, uint32_t vlen)
{
uint32_t sew = getSew(vtype.vsew);
// vlmax is defined in RVV 1.0 spec p12 chapter 3.4.2.
uint32_t vlmax = (vlen/sew) * getVflmul(vtype.vlmul);
return vlmax;
}
std::string
VConfOp::generateDisassembly(Addr pc, const loader::SymbolTable *symtab) const
{
std::stringstream ss;
ss << mnemonic << ' ' << registerName(destRegIdx(0)) << ", ";
if (bit31 && bit30 == 0) {
ss << registerName(srcRegIdx(0)) << ", " << registerName(srcRegIdx(1));
} else if (bit31 && bit30) {
ss << uimm << ", " << generateZimmDisassembly();
} else {
ss << registerName(srcRegIdx(0)) << ", " << generateZimmDisassembly();
}
return ss.str();
}
std::string
VConfOp::generateZimmDisassembly() const
{
std::stringstream s;
// VSETIVLI uses ZIMM10 and VSETVLI uses ZIMM11
uint64_t zimm = (bit31 && bit30) ? zimm10 : zimm11;
bool frac_lmul = bits(zimm, 2);
int sew = 1 << (bits(zimm, 5, 3) + 3);
int lmul = bits(zimm, 1, 0);
auto vta = bits(zimm, 6) == 1 ? "ta" : "tu";
auto vma = bits(zimm, 7) == 1 ? "ma" : "mu";
s << "e" << sew;
if (frac_lmul) {
std::string lmul_str = "";
switch(lmul){
case 3:
lmul_str = "f2";
break;
case 2:
lmul_str = "f4";
break;
case 1:
lmul_str = "f8";
break;
default:
panic("Unsupport fractional LMUL");
}
s << ", m" << lmul_str;
} else {
s << ", m" << (1 << lmul);
}
s << ", " << vta << ", " << vma;
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
{
std::stringstream ss;
ss << mnemonic << ' ' << registerName(destRegIdx(0)) << ", "
<< VLENB * microIdx << '(' << registerName(srcRegIdx(0)) << ')' << ", "
<< registerName(srcRegIdx(1));
if (!machInst.vm) ss << ", v0.t";
return ss.str();
}
std::string VlWholeMicroInst::generateDisassembly(Addr pc,
const loader::SymbolTable *symtab) const
{
std::stringstream ss;
ss << mnemonic << ' ' << registerName(destRegIdx(0)) << ", "
<< VLENB * microIdx << '(' << registerName(srcRegIdx(0)) << ')';
return ss.str();
}
std::string VseMicroInst::generateDisassembly(Addr pc,
const loader::SymbolTable *symtab) const
{
std::stringstream ss;
ss << mnemonic << ' ' << registerName(srcRegIdx(1)) << ", "
<< VLENB * microIdx << '(' << registerName(srcRegIdx(0)) << ')';
if (!machInst.vm) ss << ", v0.t";
return ss.str();
}
std::string VsWholeMicroInst::generateDisassembly(Addr pc,
const loader::SymbolTable *symtab) const
{
std::stringstream ss;
ss << mnemonic << ' ' << registerName(srcRegIdx(1)) << ", "
<< VLENB * microIdx << '(' << registerName(srcRegIdx(0)) << ')';
return ss.str();
}
std::string VleMacroInst::generateDisassembly(Addr pc,
const loader::SymbolTable *symtab) const
{
std::stringstream ss;
ss << mnemonic << ' ' << registerName(destRegIdx(0)) << ", " <<
'(' << registerName(srcRegIdx(0)) << ')';
if (!machInst.vm) ss << ", v0.t";
return ss.str();
}
std::string VlWholeMacroInst::generateDisassembly(Addr pc,
const loader::SymbolTable *symtab) const
{
std::stringstream ss;
ss << mnemonic << ' ' << registerName(destRegIdx(0)) << ", " <<
'(' << registerName(srcRegIdx(0)) << ')';
return ss.str();
}
std::string VseMacroInst::generateDisassembly(Addr pc,
const loader::SymbolTable *symtab) const
{
std::stringstream ss;
ss << mnemonic << ' ' << registerName(srcRegIdx(1)) << ", " <<
'(' << registerName(srcRegIdx(0)) << ')';
if (!machInst.vm) ss << ", v0.t";
return ss.str();
}
std::string VsWholeMacroInst::generateDisassembly(Addr pc,
const loader::SymbolTable *symtab) const
{
std::stringstream ss;
ss << mnemonic << ' ' << registerName(srcRegIdx(1)) << ", " <<
'(' << registerName(srcRegIdx(0)) << ')';
return ss.str();
}
std::string VlStrideMacroInst::generateDisassembly(Addr pc,
const loader::SymbolTable *symtab) const
{
std::stringstream ss;
ss << mnemonic << ' ' << registerName(destRegIdx(0)) << ", " <<
'(' << registerName(srcRegIdx(0)) << ')' <<
", " << registerName(srcRegIdx(1));
if (!machInst.vm) ss << ", v0.t";
return ss.str();
}
std::string VlStrideMicroInst::generateDisassembly(Addr pc,
const loader::SymbolTable *symtab) const
{
std::stringstream ss;
ss << mnemonic << ' ' << registerName(destRegIdx(0)) << ", " <<
'(' << registerName(srcRegIdx(0)) << ')' <<
", "<< registerName(srcRegIdx(1));
if (microIdx != 0 || machInst.vtype8.vma == 0 || machInst.vtype8.vta == 0)
ss << ", " << registerName(srcRegIdx(2));
if (!machInst.vm) ss << ", v0.t";
return ss.str();
}
std::string VsStrideMacroInst::generateDisassembly(Addr pc,
const loader::SymbolTable *symtab) const
{
std::stringstream ss;
ss << mnemonic << ' ' << registerName(srcRegIdx(2)) << ", " <<
'(' << registerName(srcRegIdx(0)) << ')' <<
", " << registerName(srcRegIdx(1));
if (!machInst.vm) ss << ", v0.t";
return ss.str();
}
std::string VsStrideMicroInst::generateDisassembly(Addr pc,
const loader::SymbolTable *symtab) const
{
std::stringstream ss;
ss << mnemonic << ' ' << registerName(srcRegIdx(2)) << ", " <<
'(' << registerName(srcRegIdx(0)) << ')' <<
", "<< registerName(srcRegIdx(1));
if (microIdx != 0 || machInst.vtype8.vma == 0 || machInst.vtype8.vta == 0)
ss << ", " << registerName(srcRegIdx(2));
if (!machInst.vm) ss << ", v0.t";
return ss.str();
}
std::string VlIndexMacroInst::generateDisassembly(Addr pc,
const loader::SymbolTable *symtab) const
{
std::stringstream ss;
ss << mnemonic << ' ' << registerName(destRegIdx(0)) << ", "
<< '(' << registerName(srcRegIdx(0)) << "),"
<< registerName(srcRegIdx(1));
if (!machInst.vm) ss << ", v0.t";
return ss.str();
}
std::string VlIndexMicroInst::generateDisassembly(Addr pc,
const loader::SymbolTable *symtab) const
{
std::stringstream ss;
ss << mnemonic << ' '
<< registerName(destRegIdx(0)) << "[" << uint16_t(vdElemIdx) << "], "
<< '(' << registerName(srcRegIdx(0)) << "), "
<< registerName(srcRegIdx(1)) << "[" << uint16_t(vs2ElemIdx) << "]";
if (microIdx != 0 || machInst.vtype8.vma == 0 || machInst.vtype8.vta == 0)
ss << ", " << registerName(srcRegIdx(2));
if (!machInst.vm) ss << ", v0.t";
return ss.str();
}
std::string VsIndexMacroInst::generateDisassembly(Addr pc,
const loader::SymbolTable *symtab) const
{
std::stringstream ss;
ss << mnemonic << ' ' << registerName(srcRegIdx(2)) << ", "
<< '(' << registerName(srcRegIdx(0)) << "),"
<< registerName(srcRegIdx(1));
if (!machInst.vm) ss << ", v0.t";
return ss.str();
}
std::string VsIndexMicroInst::generateDisassembly(Addr pc,
const loader::SymbolTable *symtab) const
{
std::stringstream ss;
ss << mnemonic << ' '
<< registerName(srcRegIdx(2)) << "[" << uint16_t(vs3ElemIdx) << "], "
<< '(' << registerName(srcRegIdx(0)) << "), "
<< registerName(srcRegIdx(1)) << "[" << uint16_t(vs2ElemIdx) << "]";
if (!machInst.vm) ss << ", v0.t";
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

@@ -0,0 +1,634 @@
/*
* 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.
*/
#ifndef __ARCH_RISCV_INSTS_VECTOR_HH__
#define __ARCH_RISCV_INSTS_VECTOR_HH__
#include <string>
#include "arch/riscv/insts/static_inst.hh"
#include "arch/riscv/regs/misc.hh"
#include "arch/riscv/regs/vector.hh"
#include "arch/riscv/utility.hh"
#include "cpu/exec_context.hh"
#include "cpu/static_inst.hh"
namespace gem5
{
namespace RiscvISA
{
float
getVflmul(uint32_t vlmul_encoding);
inline uint32_t
getSew(uint32_t vsew)
{
assert(vsew <= 3);
return (8 << vsew);
}
uint32_t
getVlmax(VTYPE vtype, uint32_t vlen);
/**
* Base class for Vector Config operations
*/
class VConfOp : public RiscvStaticInst
{
protected:
uint64_t bit30;
uint64_t bit31;
uint64_t zimm10;
uint64_t zimm11;
uint64_t uimm;
VConfOp(const char *mnem, ExtMachInst _extMachInst, OpClass __opClass)
: RiscvStaticInst(mnem, _extMachInst, __opClass),
bit30(_extMachInst.bit30), bit31(_extMachInst.bit31),
zimm10(_extMachInst.zimm_vsetivli),
zimm11(_extMachInst.zimm_vsetvli),
uimm(_extMachInst.uimm_vsetivli)
{}
std::string generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const override;
std::string generateZimmDisassembly() const;
};
inline uint8_t checked_vtype(bool vill, uint8_t vtype) {
panic_if(vill, "vill has been set");
const uint8_t vsew = bits(vtype, 5, 3);
panic_if(vsew >= 0b100, "vsew: %#x not supported", vsew);
const uint8_t vlmul = bits(vtype, 2, 0);
panic_if(vlmul == 0b100, "vlmul: %#x not supported", vlmul);
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:
uint32_t vl;
uint8_t vtype;
VectorMacroInst(const char* mnem, ExtMachInst _machInst,
OpClass __opClass)
: RiscvMacroInst(mnem, _machInst, __opClass),
vl(_machInst.vl),
vtype(checked_vtype(_machInst.vill, _machInst.vtype8))
{
this->flags[IsVector] = true;
}
};
class VectorMicroInst : public RiscvMicroInst
{
protected:
uint8_t microVl;
uint8_t microIdx;
uint8_t vtype;
VectorMicroInst(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
uint8_t _microVl, uint8_t _microIdx)
: RiscvMicroInst(mnem, _machInst, __opClass),
microVl(_microVl),
microIdx(_microIdx),
vtype(_machInst.vtype8)
{
this->flags[IsVector] = true;
}
};
class VectorNopMicroInst : public RiscvMicroInst
{
public:
VectorNopMicroInst(ExtMachInst _machInst)
: RiscvMicroInst("vnop", _machInst, No_OpClass)
{}
Fault execute(ExecContext* xc, trace::InstRecord* traceData)
const override
{
return NoFault;
}
std::string generateDisassembly(Addr pc, const loader::SymbolTable *symtab)
const override
{
std::stringstream ss;
ss << mnemonic;
return ss.str();
}
};
class VectorArithMicroInst : public VectorMicroInst
{
protected:
VectorArithMicroInst(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 VectorArithMacroInst : public VectorMacroInst
{
protected:
VectorArithMacroInst(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 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:
uint32_t offset; // Used to calculate EA.
Request::Flags memAccessFlags;
VectorMemMicroInst(const char* mnem, ExtMachInst _machInst,
OpClass __opClass, uint8_t _microVl, uint8_t _microIdx,
uint32_t _offset)
: VectorMicroInst(mnem, _machInst, __opClass, _microVl, _microIdx)
, offset(_offset)
, memAccessFlags(0)
{}
};
class VectorMemMacroInst : public VectorMacroInst
{
protected:
VectorMemMacroInst(const char* mnem, ExtMachInst _machInst,
OpClass __opClass)
: VectorMacroInst(mnem, _machInst, __opClass)
{}
};
class VleMacroInst : public VectorMemMacroInst
{
protected:
VleMacroInst(const char* mnem, ExtMachInst _machInst,
OpClass __opClass)
: VectorMemMacroInst(mnem, _machInst, __opClass)
{}
std::string generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const override;
};
class VseMacroInst : public VectorMemMacroInst
{
protected:
VseMacroInst(const char* mnem, ExtMachInst _machInst,
OpClass __opClass)
: VectorMemMacroInst(mnem, _machInst, __opClass)
{}
std::string generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const override;
};
class VleMicroInst : public VectorMicroInst
{
protected:
Request::Flags memAccessFlags;
VleMicroInst(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
uint8_t _microVl, uint8_t _microIdx)
: VectorMicroInst(mnem, _machInst, __opClass, _microVl, _microIdx)
{
this->flags[IsLoad] = true;
}
std::string generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const override;
};
class VseMicroInst : public VectorMicroInst
{
protected:
Request::Flags memAccessFlags;
VseMicroInst(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
uint8_t _microVl, uint8_t _microIdx)
: VectorMicroInst(mnem, _machInst, __opClass, _microVl, _microIdx)
{
this->flags[IsStore] = true;
}
std::string generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const override;
};
class VlWholeMacroInst : public VectorMemMacroInst
{
protected:
VlWholeMacroInst(const char *mnem, ExtMachInst _machInst,
OpClass __opClass)
: VectorMemMacroInst(mnem, _machInst, __opClass)
{}
std::string generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const override;
};
class VlWholeMicroInst : public VectorMicroInst
{
protected:
Request::Flags memAccessFlags;
VlWholeMicroInst(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 VsWholeMacroInst : public VectorMemMacroInst
{
protected:
VsWholeMacroInst(const char *mnem, ExtMachInst _machInst,
OpClass __opClass)
: VectorMemMacroInst(mnem, _machInst, __opClass)
{}
std::string generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const override;
};
class VsWholeMicroInst : public VectorMicroInst
{
protected:
Request::Flags memAccessFlags;
VsWholeMicroInst(const char *mnem, ExtMachInst _machInst,
OpClass __opClass, uint8_t _microVl, uint8_t _microIdx)
: VectorMicroInst(mnem, _machInst, __opClass, _microIdx, _microIdx)
{}
std::string generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const override;
};
class VlStrideMacroInst : public VectorMemMacroInst
{
protected:
VlStrideMacroInst(const char* mnem, ExtMachInst _machInst,
OpClass __opClass)
: VectorMemMacroInst(mnem, _machInst, __opClass)
{}
std::string generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const override;
};
class VlStrideMicroInst : public VectorMemMicroInst
{
protected:
uint8_t regIdx;
VlStrideMicroInst(const char *mnem, ExtMachInst _machInst,
OpClass __opClass, uint8_t _regIdx,
uint8_t _microIdx, uint8_t _microVl)
: VectorMemMicroInst(mnem, _machInst, __opClass, _microVl,
_microIdx, 0)
, regIdx(_regIdx)
{}
std::string generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const override;
};
class VsStrideMacroInst : public VectorMemMacroInst
{
protected:
VsStrideMacroInst(const char* mnem, ExtMachInst _machInst,
OpClass __opClass)
: VectorMemMacroInst(mnem, _machInst, __opClass)
{}
std::string generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const override;
};
class VsStrideMicroInst : public VectorMemMicroInst
{
protected:
uint8_t regIdx;
VsStrideMicroInst(const char *mnem, ExtMachInst _machInst,
OpClass __opClass, uint8_t _regIdx,
uint8_t _microIdx, uint8_t _microVl)
: VectorMemMicroInst(mnem, _machInst, __opClass, _microVl,
_microIdx, 0)
, regIdx(_regIdx)
{}
std::string generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const override;
};
class VlIndexMacroInst : public VectorMemMacroInst
{
protected:
VlIndexMacroInst(const char* mnem, ExtMachInst _machInst,
OpClass __opClass)
: VectorMemMacroInst(mnem, _machInst, __opClass)
{}
std::string generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const override;
};
class VlIndexMicroInst : public VectorMemMicroInst
{
protected:
uint8_t vdRegIdx;
uint8_t vdElemIdx;
uint8_t vs2RegIdx;
uint8_t vs2ElemIdx;
VlIndexMicroInst(const char *mnem, ExtMachInst _machInst,
OpClass __opClass, uint8_t _vdRegIdx, uint8_t _vdElemIdx,
uint8_t _vs2RegIdx, uint8_t _vs2ElemIdx)
: VectorMemMicroInst(mnem, _machInst, __opClass, 1,
0, 0)
, vdRegIdx(_vdRegIdx), vdElemIdx(_vdElemIdx)
, vs2RegIdx(_vs2RegIdx), vs2ElemIdx(_vs2ElemIdx)
{}
std::string generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const override;
};
class VsIndexMacroInst : public VectorMemMacroInst
{
protected:
VsIndexMacroInst(const char* mnem, ExtMachInst _machInst,
OpClass __opClass)
: VectorMemMacroInst(mnem, _machInst, __opClass)
{}
std::string generateDisassembly(
Addr pc, const loader::SymbolTable *symtab) const override;
};
class VsIndexMicroInst : public VectorMemMicroInst
{
protected:
uint8_t vs3RegIdx;
uint8_t vs3ElemIdx;
uint8_t vs2RegIdx;
uint8_t vs2ElemIdx;
VsIndexMicroInst(const char *mnem, ExtMachInst _machInst,
OpClass __opClass, uint8_t _vs3RegIdx, uint8_t _vs3ElemIdx,
uint8_t _vs2RegIdx, uint8_t _vs2ElemIdx)
: VectorMemMicroInst(mnem, _machInst, __opClass, 1, 0, 0),
vs3RegIdx(_vs3RegIdx), vs3ElemIdx(_vs3ElemIdx),
vs2RegIdx(_vs2RegIdx), vs2ElemIdx(_vs2ElemIdx)
{}
std::string generateDisassembly(
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
#endif // __ARCH_RISCV_INSTS_VECTOR_HH__

View File

@@ -43,6 +43,7 @@
#include "arch/riscv/regs/float.hh"
#include "arch/riscv/regs/int.hh"
#include "arch/riscv/regs/misc.hh"
#include "arch/riscv/regs/vector.hh"
#include "base/bitfield.hh"
#include "base/compiler.hh"
#include "base/logging.hh"
@@ -52,6 +53,7 @@
#include "debug/LLSC.hh"
#include "debug/MatRegs.hh"
#include "debug/RiscvMisc.hh"
#include "debug/VecRegs.hh"
#include "mem/packet.hh"
#include "mem/request.hh"
#include "params/RiscvISA.hh"
@@ -189,6 +191,14 @@ namespace RiscvISA
[MISCREG_FFLAGS] = "FFLAGS",
[MISCREG_FRM] = "FRM",
[MISCREG_VSTART] = "VSTART",
[MISCREG_VXSAT] = "VXSAT",
[MISCREG_VXRM] = "VXRM",
[MISCREG_VCSR] = "VCSR",
[MISCREG_VL] = "VL",
[MISCREG_VTYPE] = "VTYPE",
[MISCREG_VLENB] = "VLENB",
[MISCREG_NMIVEC] = "NMIVEC",
[MISCREG_NMIE] = "NMIE",
[MISCREG_NMIP] = "NMIP",
@@ -234,17 +244,18 @@ namespace
{
/* Not applicable to RISCV */
RegClass vecRegClass(VecRegClass, VecRegClassName, 1, debug::IntRegs);
RegClass vecElemClass(VecElemClass, VecElemClassName, 2, debug::IntRegs);
RegClass vecPredRegClass(VecPredRegClass, VecPredRegClassName, 1,
RegClass vecElemClass(VecElemClass, VecElemClassName, 0, debug::IntRegs);
RegClass vecPredRegClass(VecPredRegClass, VecPredRegClassName, 0,
debug::IntRegs);
RegClass matRegClass(MatRegClass, MatRegClassName, 1, debug::MatRegs);
RegClass matRegClass(MatRegClass, MatRegClassName, 0, debug::MatRegs);
RegClass ccRegClass(CCRegClass, CCRegClassName, 0, debug::IntRegs);
} // anonymous namespace
ISA::ISA(const Params &p) :
BaseISA(p), _rvType(p.riscv_type), checkAlignment(p.check_alignment)
BaseISA(p), _rvType(p.riscv_type), checkAlignment(p.check_alignment),
enableRvv(p.enable_rvv)
{
_regClasses.push_back(&intRegClass);
_regClasses.push_back(&floatRegClass);
@@ -275,6 +286,13 @@ ISA::copyRegsFrom(ThreadContext *src)
for (auto &id: floatRegClass)
tc->setReg(id, src->getReg(id));
// Third loop through the vector registers.
RiscvISA::VecRegContainer vc;
for (auto &id: vecRegClass) {
src->getReg(id, &vc);
tc->setReg(id, &vc);
}
// Lastly copy PC/NPC
tc->pcState(src->pcState());
}
@@ -307,6 +325,10 @@ void ISA::clear()
case RV64:
misa.rv64_mxl = 2;
status.uxl = status.sxl = 2;
if (getEnableRvv()) {
status.vs = VPUStatus::INITIAL;
misa.rvv = 1;
}
break;
default:
panic("%s: Unknown _rvType: %d", name(), (int)_rvType);
@@ -479,6 +501,17 @@ ISA::readMiscReg(RegIndex idx)
return readMiscRegNoEffect(idx);
}
case MISCREG_VLENB:
{
return VLENB;
}
break;
case MISCREG_VCSR:
{
return readMiscRegNoEffect(MISCREG_VXSAT) &
(readMiscRegNoEffect(MISCREG_VXRM) << 1);
}
break;
default:
// Try reading HPM counters
// As a placeholder, all HPM counters are just cycle counters
@@ -652,6 +685,22 @@ ISA::setMiscReg(RegIndex idx, RegVal val)
setMiscRegNoEffect(idx, val);
}
break;
case MISCREG_VXSAT:
{
setMiscRegNoEffect(idx, val & 0x1);
}
break;
case MISCREG_VXRM:
{
setMiscRegNoEffect(idx, val & 0x3);
}
break;
case MISCREG_VCSR:
{
setMiscRegNoEffect(MISCREG_VXSAT, val & 0x1);
setMiscRegNoEffect(MISCREG_VXRM, (val & 0x6) >> 1);
}
break;
default:
setMiscRegNoEffect(idx, val);
}

View File

@@ -67,12 +67,15 @@ enum FPUStatus
DIRTY = 3,
};
using VPUStatus = FPUStatus;
class ISA : public BaseISA
{
protected:
RiscvType _rvType;
std::vector<RegVal> miscRegFile;
bool checkAlignment;
bool enableRvv;
bool hpmCounterEnabled(int counter) const;
@@ -136,6 +139,8 @@ class ISA : public BaseISA
RiscvType rvType() const { return _rvType; }
bool getEnableRvv() const { return enableRvv; }
void
clearLoadReservation(ContextID cid)
{

View File

@@ -133,3 +133,27 @@ def bitfield BIT25 <25>;
def bitfield RNUM <23:20>;
def bitfield KFUNCT5 <29:25>;
def bitfield BS <31:30>;
// Vector instructions
def bitfield VFUNCT6 vfunct6;
def bitfield VFUNCT5 vfunct5;
def bitfield VFUNCT3 vfunct3;
def bitfield VFUNCT2 vfunct2;
def bitfield VS3 vs3;
def bitfield VS2 vs2;
def bitfield VS1 vs1;
def bitfield VD vd;
def bitfield NF nf;
def bitfield MEW mew;
def bitfield MOP mop;
def bitfield VM vm;
def bitfield LUMOP lumop;
def bitfield SUMOP sumop;
def bitfield WIDTH width;
def bitfield BIT31 bit31;
def bitfield BIT30 bit30;
def bitfield SIMM5 uimm_vsetivli;
def bitfield SIMM3 simm3;

File diff suppressed because it is too large Load Diff

View File

@@ -37,6 +37,9 @@
##include "fp.isa"
##include "amo.isa"
##include "bs.isa"
##include "vector_conf.isa"
##include "vector_arith.isa"
##include "vector_mem.isa"
// Include formats for nonstandard extensions
##include "compressed.isa"

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,96 @@
// -*- 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 format VConfOp(code, *flags) {{
iop = InstObjParams(name, Name, 'VConfOp', code, flags)
header_output = BasicDeclare.subst(iop)
decoder_output = BasicConstructor.subst(iop)
decode_block = BasicDecode.subst(iop)
exec_output = VConfExecute.subst(iop)
}};
def template VConfExecute {{
Fault
%(class_name)s::execute(ExecContext *xc,
trace::InstRecord *traceData) const
{
auto tc = xc->tcBase();
%(op_decl)s;
%(op_rd)s;
%(code)s;
tc->setMiscReg(MISCREG_VSTART, 0);
uint32_t vlen = xc->readMiscReg(MISCREG_VLENB) * 8;
uint32_t vlmax = getVlmax(xc->readMiscReg(MISCREG_VTYPE), vlen);
VTYPE new_vtype = requested_vtype;
if (xc->readMiscReg(MISCREG_VTYPE) != new_vtype) {
vlmax = getVlmax(new_vtype, vlen);
float vflmul = getVflmul(new_vtype.vlmul);
uint32_t sew = getSew(new_vtype.vsew);
uint32_t new_vill =
!(vflmul >= 0.125 && vflmul <= 8) ||
sew > std::min(vflmul, 1.0f) * ELEN ||
bits(requested_vtype, 30, 8) != 0;
if (new_vill) {
vlmax = 0;
new_vtype = 0;
new_vtype.vill = 1;
}
xc->setMiscReg(MISCREG_VTYPE, new_vtype);
}
uint32_t current_vl = xc->readMiscReg(MISCREG_VL);
uint32_t new_vl = 0;
if (vlmax == 0) {
new_vl = 0;
} else if (rd_bits == 0 && rs1_bits == 0) {
new_vl = current_vl > vlmax ? vlmax : current_vl;
} else if (rd_bits != 0 && rs1_bits == 0) {
new_vl = vlmax;
} else if (rs1_bits != 0) {
new_vl = requested_vl > vlmax ? vlmax : requested_vl;
}
xc->setMiscReg(MISCREG_VL, new_vl);
tc->getDecoderPtr()->as<Decoder>().setVlAndVtype(new_vl, new_vtype);
Rd = new_vl;
%(op_wb)s;
return NoFault;
}
}};

View File

@@ -0,0 +1,205 @@
// -*- 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.
let {{
def VMemBase(name, Name, ea_code, memacc_code, mem_flags,
inst_flags, base_class, postacc_code='',
declare_template_base=VMemMacroDeclare,
decode_template=BasicDecode, exec_template_base='',
# If it's a macroop, the corresponding microops will be
# generated.
is_macroop=True):
# Make sure flags are in lists (convert to lists if not).
mem_flags = makeList(mem_flags)
inst_flags = makeList(inst_flags)
iop = InstObjParams(name, Name, base_class,
{'ea_code': ea_code,
'memacc_code': memacc_code,
'postacc_code': postacc_code },
inst_flags)
constructTemplate = eval(exec_template_base + 'Constructor')
header_output = declare_template_base.subst(iop)
decoder_output = ''
if declare_template_base is not VMemTemplateMacroDeclare:
decoder_output += constructTemplate.subst(iop)
else:
header_output += constructTemplate.subst(iop)
decode_block = decode_template.subst(iop)
exec_output = ''
if not is_macroop:
return (header_output, decoder_output, decode_block, exec_output)
microiop = InstObjParams(name + '_micro',
Name + 'Micro',
exec_template_base + 'MicroInst',
{'ea_code': ea_code,
'memacc_code': memacc_code,
'postacc_code': postacc_code},
inst_flags)
if mem_flags:
mem_flags = [ 'Request::%s' % flag for flag in mem_flags ]
s = '\n\tmemAccessFlags = ' + '|'.join(mem_flags) + ';'
microiop.constructor += s
microDeclTemplate = eval(exec_template_base + 'Micro' + 'Declare')
microExecTemplate = eval(exec_template_base + 'Micro' + 'Execute')
microInitTemplate = eval(exec_template_base + 'Micro' + 'InitiateAcc')
microCompTemplate = eval(exec_template_base + 'Micro' + 'CompleteAcc')
header_output = microDeclTemplate.subst(microiop) + header_output
micro_exec_output = (microExecTemplate.subst(microiop) +
microInitTemplate.subst(microiop) +
microCompTemplate.subst(microiop))
if declare_template_base is not VMemTemplateMacroDeclare:
exec_output += micro_exec_output
else:
header_output += micro_exec_output
return (header_output, decoder_output, decode_block, exec_output)
}};
def format VleOp(
memacc_code,
ea_code={{ EA = Rs1 + VLENB * microIdx; }},
mem_flags=[],
inst_flags=[]
) {{
(header_output, decoder_output, decode_block, exec_output) = \
VMemBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
'VleMacroInst', exec_template_base='Vle')
}};
def format VseOp(
memacc_code,
ea_code={{ EA = Rs1 + VLENB * microIdx; }},
mem_flags=[],
inst_flags=[]
) {{
(header_output, decoder_output, decode_block, exec_output) = \
VMemBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
'VseMacroInst', exec_template_base='Vse')
}};
def format VlmOp(
memacc_code,
ea_code={{ EA = Rs1; }},
mem_flags=[],
inst_flags=[]
) {{
(header_output, decoder_output, decode_block, exec_output) = \
VMemBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
'VleMacroInst', exec_template_base='Vlm', is_macroop=False)
}};
def format VsmOp(
memacc_code,
ea_code={{ EA = Rs1; }},
mem_flags=[],
inst_flags=[]
) {{
(header_output, decoder_output, decode_block, exec_output) = \
VMemBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
'VseMacroInst', exec_template_base='Vsm', is_macroop=False)
}};
def format VlWholeOp(
memacc_code,
ea_code={{ EA = Rs1 + VLENB * microIdx; }},
mem_flags=[],
inst_flags=[]
) {{
(header_output, decoder_output, decode_block, exec_output) = \
VMemBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
'VlWholeMacroInst', exec_template_base='VlWhole')
}};
def format VsWholeOp(
memacc_code,
ea_code={{ EA = Rs1 + VLENB * microIdx; }},
mem_flags=[],
inst_flags=[]
) {{
(header_output, decoder_output, decode_block, exec_output) = \
VMemBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
'VsWholeMacroInst', exec_template_base='VsWhole')
}};
def format VlStrideOp(
memacc_code,
ea_code={{ EA = Rs1 + Rs2 * (regIdx * VLENB / elem_size + microIdx); }},
mem_flags=[],
inst_flags=[]
) {{
(header_output, decoder_output, decode_block, exec_output) = \
VMemBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
'VlStrideMacroInst', exec_template_base='VlStride')
}};
def format VsStrideOp(
memacc_code,
ea_code={{ EA = Rs1 + Rs2 * (regIdx * VLENB / elem_size + microIdx); }},
mem_flags=[],
inst_flags=[]
) {{
(header_output, decoder_output, decode_block, exec_output) = \
VMemBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
'VsStrideMacroInst', exec_template_base='VsStride')
}};
def format VlIndexOp(
memacc_code,
ea_code,
mem_flags=[],
inst_flags=[]
) {{
(header_output, decoder_output, decode_block, exec_output) = \
VMemBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
'VlIndexMacroInst', exec_template_base='VlIndex',
declare_template_base=VMemTemplateMacroDeclare,
decode_template=VMemTemplateDecodeBlock
)
}};
def format VsIndexOp(
memacc_code,
ea_code,
mem_flags=[],
inst_flags=[]
) {{
(header_output, decoder_output, decode_block, exec_output) = \
VMemBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
'VsIndexMacroInst', exec_template_base='VsIndex',
declare_template_base=VMemTemplateMacroDeclare,
decode_template=VMemTemplateDecodeBlock
)
}};

View File

@@ -34,6 +34,7 @@
//
output header {{
#include <functional>
#include <iomanip>
#include <sstream>
#include <string>
@@ -45,6 +46,8 @@ output header {{
#include <softfloat.h>
#include <specialize.h>
#include "arch/generic/memhelpers.hh"
#include "arch/riscv/decoder.hh"
#include "arch/riscv/insts/amo.hh"
#include "arch/riscv/insts/bs.hh"
#include "arch/riscv/insts/compressed.hh"
@@ -53,6 +56,7 @@ output header {{
#include "arch/riscv/insts/standard.hh"
#include "arch/riscv/insts/static_inst.hh"
#include "arch/riscv/insts/unknown.hh"
#include "arch/riscv/insts/vector.hh"
#include "arch/riscv/interrupts.hh"
#include "cpu/static_inst.hh"
#include "mem/packet.hh"
@@ -66,9 +70,15 @@ output decoder {{
#include <limits>
#include <string>
/* riscv softfloat library */
#include <internals.h>
#include <softfloat.h>
#include <specialize.h>
#include "arch/riscv/decoder.hh"
#include "arch/riscv/faults.hh"
#include "arch/riscv/mmu.hh"
#include "arch/riscv/regs/float.hh"
#include "base/cprintf.hh"
#include "base/loader/symtab.hh"
#include "cpu/thread_context.hh"
@@ -95,6 +105,7 @@ output exec {{
#include "arch/riscv/reg_abi.hh"
#include "arch/riscv/regs/float.hh"
#include "arch/riscv/regs/misc.hh"
#include "arch/riscv/regs/vector.hh"
#include "arch/riscv/utility.hh"
#include "base/condcodes.hh"
#include "cpu/base.hh"

View File

@@ -50,6 +50,9 @@ namespace RiscvISA;
//Include the operand_types and operand definitions
##include "operands.isa"
//Include the definitions for the instruction templates
##include "templates/templates.isa"
//Include the definitions for the instruction formats
##include "formats/formats.isa"

View File

@@ -38,7 +38,15 @@ def operand_types {{
'sd' : 'int64_t',
'ud' : 'uint64_t',
'sf' : 'float',
'df' : 'double'
'df' : 'double',
'vi' : 'vi',
'vu' : 'vu',
'vwi' : 'vwi',
'vwu' : 'vwu',
'vext' : 'vext',
'vextu' : 'vextu',
'vc' : 'RiscvISA::VecRegContainer'
}};
let {{
@@ -79,6 +87,11 @@ def operands {{
'Fp2': FloatRegOp('df', 'FP2 + 8', 'IsFloating', 2),
'Fp2_bits': FloatRegOp('ud', 'FP2 + 8', 'IsFloating', 2),
'Vd': VecRegOp('vc', 'VD', 'IsVector', 1),
'Vs1': VecRegOp('vc', 'VS1', 'IsVector', 2),
'Vs2': VecRegOp('vc', 'VS2', 'IsVector', 3),
'Vs3': VecRegOp('vc', 'VS3', 'IsVector', 4),
#Memory Operand
'Mem': MemOp('ud', None, (None, 'IsLoad', 'IsStore'), 5),

View File

@@ -0,0 +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

File diff suppressed because it is too large Load Diff

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

@@ -191,6 +191,14 @@ enum MiscRegIndex
MISCREG_FFLAGS,
MISCREG_FRM,
MISCREG_VSTART,
MISCREG_VXSAT,
MISCREG_VXRM,
MISCREG_VCSR,
MISCREG_VL,
MISCREG_VTYPE,
MISCREG_VLENB,
// These registers are not in the standard, hence does not exist in the
// CSRData map. These are mainly used to provide a minimal implementation
// for non-maskable-interrupt in our simple cpu.
@@ -476,7 +484,15 @@ enum CSRIndex
CSR_TDATA3 = 0x7A3,
CSR_DCSR = 0x7B0,
CSR_DPC = 0x7B1,
CSR_DSCRATCH = 0x7B2
CSR_DSCRATCH = 0x7B2,
CSR_VSTART = 0x008,
CSR_VXSAT = 0x009,
CSR_VXRM = 0x00A,
CSR_VCSR = 0x00F,
CSR_VL = 0xC20,
CSR_VTYPE = 0xC21,
CSR_VLENB = 0xC22
};
struct CSRMetadata
@@ -718,7 +734,15 @@ const std::unordered_map<int, CSRMetadata> CSRData = {
{CSR_TDATA3, {"tdata3", MISCREG_TDATA3, rvTypeFlags(RV64, RV32)}},
{CSR_DCSR, {"dcsr", MISCREG_DCSR, rvTypeFlags(RV64, RV32)}},
{CSR_DPC, {"dpc", MISCREG_DPC, rvTypeFlags(RV64, RV32)}},
{CSR_DSCRATCH, {"dscratch", MISCREG_DSCRATCH, rvTypeFlags(RV64, RV32)}}
{CSR_DSCRATCH, {"dscratch", MISCREG_DSCRATCH, rvTypeFlags(RV64, RV32)}},
{CSR_VSTART, {"vstart", MISCREG_VSTART, rvTypeFlags(RV64, RV32)}},
{CSR_VXSAT, {"vxsat" , MISCREG_VXSAT, rvTypeFlags(RV64, RV32)}},
{CSR_VXRM, {"vxrm" , MISCREG_VXRM, rvTypeFlags(RV64, RV32)}},
{CSR_VCSR, {"vcsr" , MISCREG_VCSR, rvTypeFlags(RV64, RV32)}},
{CSR_VL, {"vl" , MISCREG_VL, rvTypeFlags(RV64, RV32)}},
{CSR_VTYPE, {"vtype" , MISCREG_VTYPE, rvTypeFlags(RV64, RV32)}},
{CSR_VLENB, {"VLENB" , MISCREG_VLENB, rvTypeFlags(RV64, RV32)}}
};
/**
@@ -816,6 +840,7 @@ const off_t SBE_OFFSET[enums::Num_RiscvType] = {
const off_t SXL_OFFSET = 34;
const off_t UXL_OFFSET = 32;
const off_t FS_OFFSET = 13;
const off_t VS_OFFSET = 9;
const off_t FRM_OFFSET = 5;
const RegVal ISA_MXL_MASKS[enums::Num_RiscvType] = {
@@ -853,7 +878,7 @@ const RegVal STATUS_MPRV_MASK = 1ULL << 17;
const RegVal STATUS_XS_MASK = 3ULL << 15;
const RegVal STATUS_FS_MASK = 3ULL << FS_OFFSET;
const RegVal STATUS_MPP_MASK = 3ULL << 11;
const RegVal STATUS_VS_MASK = 3ULL << 9;
const RegVal STATUS_VS_MASK = 3ULL << VS_OFFSET;
const RegVal STATUS_SPP_MASK = 1ULL << 8;
const RegVal STATUS_MPIE_MASK = 1ULL << 7;
const RegVal STATUS_SPIE_MASK = 1ULL << 5;

View File

@@ -0,0 +1,90 @@
/*
* 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.
*/
#ifndef __ARCH_RISCV_REGS_VECTOR_HH__
#define __ARCH_RISCV_REGS_VECTOR_HH__
#include <cstdint>
#include <string>
#include <vector>
#include "arch/generic/vec_pred_reg.hh"
#include "arch/generic/vec_reg.hh"
#include "base/bitunion.hh"
#include "cpu/reg_class.hh"
#include "debug/VecRegs.hh"
namespace gem5
{
namespace RiscvISA
{
constexpr unsigned ELEN = 64;
constexpr unsigned VLEN = 256;
constexpr unsigned VLENB = VLEN / 8;
using VecRegContainer = gem5::VecRegContainer<VLENB>;
using vreg_t = VecRegContainer;
const int NumVecStandardRegs = 32;
const int NumVecInternalRegs = 8; // Used by vector uop
const int NumVecRegs = NumVecStandardRegs + NumVecInternalRegs;
const std::vector<std::string> VecRegNames = {
"v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",
"v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15",
"v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
"v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31",
"vtmp0", "vtmp1", "vtmp2", "vtmp3", "vtmp4", "vtmp5", "vtmp6", "vtmp7"
};
// vector index
const int VecMemInternalReg0 = NumVecStandardRegs;
static inline TypedRegClassOps<RiscvISA::VecRegContainer> vecRegClassOps;
inline constexpr RegClass vecRegClass =
RegClass(VecRegClass, VecRegClassName, NumVecRegs, debug::VecRegs).
ops(vecRegClassOps).
regType<VecRegContainer>();
BitUnion32(VTYPE)
Bitfield<31> vill;
Bitfield<7, 0> vtype8;
Bitfield<7> vma;
Bitfield<6> vta;
Bitfield<5, 3> vsew;
Bitfield<2, 0> vlmul;
EndBitUnion(VTYPE)
} // namespace RiscvISA
} // namespace gem5
#endif // __ARCH_RISCV_REGS_VECTOR_HH__

View File

@@ -51,6 +51,7 @@
#include "arch/riscv/regs/float.hh"
#include "arch/riscv/regs/int.hh"
#include "arch/riscv/regs/vector.hh"
#include "base/types.hh"
#include "cpu/reg_class.hh"
#include "cpu/static_inst.hh"
@@ -130,7 +131,14 @@ registerName(RegId reg)
return str.str();
}
return float_reg::RegNames[reg.index()];
} else {
} else if (reg.is(VecRegClass)) {
if (reg.index() >= NumVecRegs) {
std::stringstream str;
str << "?? (v" << reg.index() << ')';
return str.str();
}
return VecRegNames[reg.index()];
} else {
/* It must be an InvalidRegClass, in RISC-V we should treat it as a
* zero register for the disassembler to work correctly.
*/
@@ -233,6 +241,542 @@ 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
* 1 000 0
* 2 001 1
* 4 010 2
* 8 011 3
* - 100 -
* 1/8 101 -3
* 1/4 110 -2
* 1/2 111 -1
*
* then, we can calculate VLMAX = vlen >> (vsew + 3 - lmul)
* e.g. vlen = 256 bits, SEW = 16, LMUL = 1/8
* => VLMAX = vlen >> (1 + 3 - (-3))
* = 256 >> 7
* = 2
* Ref: https://github.com/qemu/qemu/blob/5e9d14f2/target/riscv/cpu.h
*/
inline uint64_t
vtype_VLMAX(const uint64_t vtype, const bool per_reg = false)
{
int64_t lmul = (int64_t)sext<3>(bits(vtype, 2, 0));
lmul = per_reg ? std::min<int64_t>(0, lmul) : lmul;
int64_t vsew = bits(vtype, 5, 3);
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)
{
switch (width) {
case 0b000: return 8;
case 0b101: return 16;
case 0b110: return 32;
case 0b111: return 64;
default: GEM5_UNREACHABLE;
}
}
/*
* Spec Section 4.5
* Ref:
* https://github.com/qemu/qemu/blob/c7d773ae/target/riscv/vector_helper.c
*/
template<typename T>
inline int
elem_mask(const T* vs, const int index)
{
static_assert(std::is_integral_v<T>);
int idx = index / (sizeof(T)*8);
int pos = index % (sizeof(T)*8);
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

View File

@@ -30,7 +30,7 @@ import os
from typing import Optional, Dict, List
from .client_api.client_wrapper import ClientWrapper
from gem5.gem5_default_config import config
from m5.util import inform
from m5.util import inform, warn
from _m5 import core
@@ -53,8 +53,38 @@ clientwrapper = None
def _get_clientwrapper():
global clientwrapper
if clientwrapper is None:
if (
"GEM5_RESOURCE_JSON" in os.environ
and "GEM5_RESOURCE_JSON_APPEND" in os.environ
):
raise Exception(
"Both GEM5_RESOURCE_JSON and GEM5_RESOURCE_JSON_APPEND are set. Please set only one of them."
)
gem5_config = {}
# If the GEM5_RESOURCE_JSON is set, use it as the only source
if "GEM5_RESOURCE_JSON" in os.environ:
json_source = {
"url": os.environ["GEM5_RESOURCE_JSON"],
"isMongo": False,
}
gem5_config["sources"] = {"GEM5_RESOURCE_JSON": json_source}
if "GEM5_CONFIG" in os.environ:
warn(
f"Both GEM5_CONFIG and GEM5_RESOURCE_JSON are set.\n"
f"GEM5_CONFIG will be ignored in favor of the GEM5_RESOURCE_JSON environment variable."
)
elif (Path().cwd().resolve() / "gem5-config.json").exists():
warn(
f"Both gem5-config.json and GEM5_RESOURCE_JSON are set.\n"
f"gem5-config.json will be ignored in favor of the GEM5_RESOURCE_JSON environment variable."
)
else:
warn(
f"GEM5_RESOURCE_JSON is set.\n"
f"gem5-default-config will be ignored in favor of the GEM5_RESOURCE_JSON environment variable."
)
# First check if the config file path is provided in the environment variable
if "GEM5_CONFIG" in os.environ:
elif "GEM5_CONFIG" in os.environ:
config_file_path = Path(os.environ["GEM5_CONFIG"])
gem5_config = getFileContent(config_file_path)
inform("Using config file specified by $GEM5_CONFIG")
@@ -68,6 +98,20 @@ def _get_clientwrapper():
else:
gem5_config = config
inform("Using default config")
# If the GEM5_RESOURCE_JSON_APPEND is set, append the resources to the gem5_config
if "GEM5_RESOURCE_JSON_APPEND" in os.environ:
json_source = {
"url": os.environ["GEM5_RESOURCE_JSON_APPEND"],
"isMongo": False,
}
gem5_config["sources"].update(
{"GEM5_RESOURCE_JSON_APPEND": json_source}
)
inform(
f"Appending resources from {os.environ['GEM5_RESOURCE_JSON_APPEND']}"
)
clientwrapper = ClientWrapper(gem5_config)
return clientwrapper