Merge branch 'develop' into riscv-fix-style
This commit is contained in:
@@ -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(
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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"
|
||||
|
||||
408
src/arch/riscv/insts/vector.cc
Normal file
408
src/arch/riscv/insts/vector.cc
Normal 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
|
||||
634
src/arch/riscv/insts/vector.hh
Normal file
634
src/arch/riscv/insts/vector.hh
Normal 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__
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
@@ -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"
|
||||
|
||||
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
96
src/arch/riscv/isa/formats/vector_conf.isa
Normal file
96
src/arch/riscv/isa/formats/vector_conf.isa
Normal 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;
|
||||
}
|
||||
}};
|
||||
205
src/arch/riscv/isa/formats/vector_mem.isa
Normal file
205
src/arch/riscv/isa/formats/vector_mem.isa
Normal 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
|
||||
)
|
||||
}};
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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),
|
||||
|
||||
|
||||
32
src/arch/riscv/isa/templates/templates.isa
Normal file
32
src/arch/riscv/isa/templates/templates.isa
Normal 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"
|
||||
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
1377
src/arch/riscv/isa/templates/vector_mem.isa
Normal file
1377
src/arch/riscv/isa/templates/vector_mem.isa
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
90
src/arch/riscv/regs/vector.hh
Normal file
90
src/arch/riscv/regs/vector.hh
Normal 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__
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user