riscv: Fix bugs with RISC-V decoder and detailed CPUs
This patch fixes some bugs that were missed with the changes to the decoder that enabled compatibility with compressed instructions. In order to accommodate speculation with variable instruction widths, a few assertions in decoder had to be changed to returning faults as the specification describes should normally happen. The rest of these assertions will be changed in a later patch. [Remove commented-out debugging line and add clarifying comment to registerName in utility.hh.] Change-Id: I3f333008430d4a905cb59547a3513f5149b43b95 Reviewed-on: https://gem5-review.googlesource.com/4041 Reviewed-by: Jason Lowe-Power <jason@lowepower.com> Maintainer: Alec Roelke <ar4jc@virginia.edu>
This commit is contained in:
@@ -37,29 +37,45 @@
|
||||
namespace RiscvISA
|
||||
{
|
||||
|
||||
static const MachInst LowerBitMask = (1 << sizeof(MachInst) * 4) - 1;
|
||||
static const MachInst UpperBitMask = LowerBitMask << sizeof(MachInst) * 4;
|
||||
|
||||
void Decoder::reset()
|
||||
{
|
||||
aligned = true;
|
||||
mid = false;
|
||||
more = true;
|
||||
emi = NoopMachInst;
|
||||
instDone = false;
|
||||
}
|
||||
|
||||
void
|
||||
Decoder::moreBytes(const PCState &pc, Addr fetchPC, MachInst inst)
|
||||
{
|
||||
DPRINTF(Decode, "Getting bytes 0x%08x from address %#x\n",
|
||||
inst, pc.pc());
|
||||
DPRINTF(Decode, "Requesting bytes 0x%08x from address %#x\n", inst,
|
||||
fetchPC);
|
||||
|
||||
bool aligned = pc.pc() % sizeof(MachInst) == 0;
|
||||
if (mid) {
|
||||
assert(!aligned);
|
||||
emi |= (inst & 0xFFFF) << 16;
|
||||
if (aligned) {
|
||||
emi = inst;
|
||||
if (compressed(emi))
|
||||
emi &= LowerBitMask;
|
||||
more = !compressed(emi);
|
||||
instDone = true;
|
||||
} else {
|
||||
MachInst instChunk = aligned ? inst & 0xFFFF :
|
||||
(inst & 0xFFFF0000) >> 16;
|
||||
if (aligned) {
|
||||
emi = (inst & 0x3) < 0x3 ? instChunk : inst;
|
||||
if (mid) {
|
||||
assert((emi & UpperBitMask) == 0);
|
||||
emi |= (inst & LowerBitMask) << sizeof(MachInst)*4;
|
||||
mid = false;
|
||||
more = false;
|
||||
instDone = true;
|
||||
} else {
|
||||
emi = instChunk;
|
||||
instDone = (instChunk & 0x3) < 0x3;
|
||||
emi = (inst & UpperBitMask) >> sizeof(MachInst)*4;
|
||||
mid = !compressed(emi);
|
||||
more = true;
|
||||
instDone = compressed(emi);
|
||||
}
|
||||
}
|
||||
mid = !instDone;
|
||||
}
|
||||
|
||||
StaticInstPtr
|
||||
@@ -83,12 +99,10 @@ Decoder::decode(RiscvISA::PCState &nextPC)
|
||||
return nullptr;
|
||||
instDone = false;
|
||||
|
||||
if ((emi & 0x3) < 0x3) {
|
||||
nextPC.compressed(true);
|
||||
nextPC.npc(nextPC.pc() + sizeof(MachInst)/2);
|
||||
if (compressed(emi)) {
|
||||
nextPC.npc(nextPC.instAddr() + sizeof(MachInst) / 2);
|
||||
} else {
|
||||
nextPC.compressed(false);
|
||||
nextPC.npc(nextPC.pc() + sizeof(MachInst));
|
||||
nextPC.npc(nextPC.instAddr() + sizeof(MachInst));
|
||||
}
|
||||
|
||||
return decode(emi, nextPC.instAddr());
|
||||
|
||||
@@ -49,7 +49,9 @@ class Decoder
|
||||
{
|
||||
private:
|
||||
DecodeCache::InstMap instMap;
|
||||
bool aligned;
|
||||
bool mid;
|
||||
bool more;
|
||||
|
||||
protected:
|
||||
//The extended machine instruction being generated
|
||||
@@ -57,18 +59,18 @@ class Decoder
|
||||
bool instDone;
|
||||
|
||||
public:
|
||||
Decoder(ISA* isa=nullptr)
|
||||
: mid(false), emi(NoopMachInst), instDone(false)
|
||||
{}
|
||||
Decoder(ISA* isa=nullptr) { reset(); }
|
||||
|
||||
void process() {}
|
||||
void reset() { instDone = false; }
|
||||
void reset();
|
||||
|
||||
inline bool compressed(ExtMachInst inst) { return (inst & 0x3) < 0x3; }
|
||||
|
||||
//Use this to give data to the decoder. This should be used
|
||||
//when there is control flow.
|
||||
void moreBytes(const PCState &pc, Addr fetchPC, MachInst inst);
|
||||
|
||||
bool needMoreBytes() { return true; }
|
||||
bool needMoreBytes() { return more; }
|
||||
bool instReady() { return instDone; }
|
||||
void takeOverFrom(Decoder *old) {}
|
||||
|
||||
|
||||
@@ -63,6 +63,13 @@ UnknownInstFault::invoke_se(ThreadContext *tc, const StaticInstPtr &inst)
|
||||
tc->pcState().pc());
|
||||
}
|
||||
|
||||
void
|
||||
IllegalInstFault::invoke_se(ThreadContext *tc, const StaticInstPtr &inst)
|
||||
{
|
||||
panic("Illegal instruction 0x%08x at pc 0x%016llx: %s", inst->machInst,
|
||||
tc->pcState().pc(), reason.c_str());
|
||||
}
|
||||
|
||||
void
|
||||
UnimplementedFault::invoke_se(ThreadContext *tc,
|
||||
const StaticInstPtr &inst)
|
||||
|
||||
@@ -116,6 +116,19 @@ class UnknownInstFault : public RiscvFault
|
||||
invoke_se(ThreadContext *tc, const StaticInstPtr &inst);
|
||||
};
|
||||
|
||||
class IllegalInstFault : public RiscvFault
|
||||
{
|
||||
private:
|
||||
const std::string reason;
|
||||
public:
|
||||
IllegalInstFault(std::string r)
|
||||
: RiscvFault("Illegal instruction", INST_ILLEGAL, SOFTWARE),
|
||||
reason(r)
|
||||
{}
|
||||
|
||||
void invoke_se(ThreadContext *tc, const StaticInstPtr &inst);
|
||||
};
|
||||
|
||||
class UnimplementedFault : public RiscvFault
|
||||
{
|
||||
private:
|
||||
|
||||
@@ -42,7 +42,8 @@ decode QUADRANT default Unknown::unknown() {
|
||||
CIMM8<7:6> << 4 |
|
||||
CIMM8<5:2> << 6;
|
||||
}}, {{
|
||||
assert(imm != 0);
|
||||
if (machInst == 0)
|
||||
fault = make_shared<IllegalInstFault>("zero instruction");
|
||||
Rp2 = sp + imm;
|
||||
}});
|
||||
format CompressedLoad {
|
||||
@@ -103,7 +104,12 @@ decode QUADRANT default Unknown::unknown() {
|
||||
if (CIMM1 > 0)
|
||||
imm |= ~((uint64_t)0x1F);
|
||||
}}, {{
|
||||
assert((RC1 == 0) == (imm == 0));
|
||||
if ((RC1 == 0) != (imm == 0)) {
|
||||
if (RC1 == 0) {
|
||||
fault = make_shared<IllegalInstFault>("source reg x0");
|
||||
} else // imm == 0
|
||||
fault = make_shared<IllegalInstFault>("immediate = 0");
|
||||
}
|
||||
Rc1_sd = Rc1_sd + imm;
|
||||
}});
|
||||
0x1: c_addiw({{
|
||||
|
||||
@@ -56,8 +56,8 @@ def template FloatExecute {{
|
||||
std::fesetround(FE_UPWARD);
|
||||
break;
|
||||
case 0x4:
|
||||
panic("Round to nearest, "
|
||||
"ties to max magnitude not implemented.");
|
||||
// Round to nearest, ties to max magnitude not implemented
|
||||
fault = make_shared<IllegalFrmFault>(ROUND_MODE);
|
||||
break;
|
||||
case 0x7: {
|
||||
uint8_t frm = xc->readMiscReg(MISCREG_FRM);
|
||||
@@ -75,8 +75,8 @@ def template FloatExecute {{
|
||||
std::fesetround(FE_UPWARD);
|
||||
break;
|
||||
case 0x4:
|
||||
panic("Round to nearest,"
|
||||
" ties to max magnitude not implemented.");
|
||||
// Round to nearest, ties to max magnitude not implemented
|
||||
fault = make_shared<IllegalFrmFault>(ROUND_MODE);
|
||||
break;
|
||||
default:
|
||||
fault = std::make_shared<IllegalFrmFault>(frm);
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "arch/riscv/registers.hh"
|
||||
@@ -133,8 +134,27 @@ inline std::string
|
||||
registerName(RegId reg)
|
||||
{
|
||||
if (reg.isIntReg()) {
|
||||
if (reg.index() >= NumIntArchRegs) {
|
||||
/*
|
||||
* This should only happen if a instruction is being speculatively
|
||||
* executed along a not-taken branch, and if that instruction's
|
||||
* width was incorrectly predecoded (i.e., it was predecoded as a
|
||||
* full instruction rather than a compressed one or vice versa).
|
||||
* It also should only happen if a debug flag is on that prints
|
||||
* disassembly information, so rather than panic the incorrect
|
||||
* value is printed for debugging help.
|
||||
*/
|
||||
std::stringstream str;
|
||||
str << "?? (x" << reg.index() << ')';
|
||||
return str.str();
|
||||
}
|
||||
return IntRegNames[reg.index()];
|
||||
} else {
|
||||
if (reg.index() >= NumFloatRegs) {
|
||||
std::stringstream str;
|
||||
str << "?? (f" << reg.index() << ')';
|
||||
return str.str();
|
||||
}
|
||||
return FloatRegNames[reg.index()];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user