riscv: Emit CSR manipulation instructions.

This commit is contained in:
Unknown W. Brackets 2022-08-25 20:30:01 -07:00
parent b5755b6cf7
commit 4a93647acb
2 changed files with 91 additions and 1 deletions

View file

@ -47,6 +47,11 @@ static inline bool SupportsAtomic() {
return true;
}
static inline bool SupportsZicsr() {
// TODO
return true;
}
enum class Opcode32 {
// Note: invalid, just used for FixupBranch.
ZERO = 0b0000000,
@ -128,6 +133,13 @@ enum class Funct3 {
FLE = 0b000,
FLT = 0b001,
FEQ = 0b010,
CSRRW = 0b001,
CSRRS = 0b010,
CSRRC = 0b011,
CSRRWI = 0b101,
CSRRSI = 0b110,
CSRRCI = 0b111,
};
enum class Funct2 {
@ -233,7 +245,7 @@ static inline u32 EncodeGI(Opcode32 opcode, RiscVReg rd, Funct3 funct3, RiscVReg
}
static inline u32 EncodeI(Opcode32 opcode, RiscVReg rd, Funct3 funct3, RiscVReg rs1, Funct12 funct12) {
return EncodeI(opcode, rd, funct3, rs1, (s32)funct12);
return EncodeI(opcode, rd, funct3, rs1, ((s32)funct12 << 20) >> 20);
}
static inline u32 EncodeGI(Opcode32 opcode, RiscVReg rd, Funct3 funct3, RiscVReg rs1, Funct12 funct12) {
@ -1043,6 +1055,10 @@ void RiscVEmitter::FCVT(FConv to, FConv from, RiscVReg rd, RiscVReg rs1, Round r
// Convert between float widths.
Funct2 fromFmt = BitsToFunct2(FConvToFloatBits(from));
Funct2 toFmt = BitsToFunct2(FConvToFloatBits(to));
if (FConvToFloatBits(to) > FConvToFloatBits(from)) {
_assert_msg_(rm == Round::DYNAMIC || rm == Round::NEAREST_EVEN, "Invalid rounding mode for widening FCVT");
rm = Round::NEAREST_EVEN;
}
Write32(EncodeR(Opcode32::OP_FP, rd, (Funct3)rm, rs1, (RiscVReg)fromFmt, toFmt, Funct5::FCVT_SZ));
} else {
Funct5 funct5 = FConvToIntegerBits(to) == 0 ? Funct5::FCVT_FROMX : Funct5::FCVT_TOX;
@ -1097,4 +1113,43 @@ void RiscVEmitter::FCLASS(int bits, RiscVReg rd, RiscVReg rs1) {
Write32(EncodeR(Opcode32::OP_FP, rd, Funct3::FCLASS, rs1, F0, BitsToFunct2(bits), Funct5::FMV_TOX));
}
void RiscVEmitter::CSRRW(RiscVReg rd, Csr csr, RiscVReg rs1) {
_assert_msg_(SupportsZicsr(), "%s instruction not supported", __func__);
_assert_msg_((u32)csr <= 0x00000FFF, "%s with invalid CSR number", __func__);
Write32(EncodeGI(Opcode32::SYSTEM, rd, Funct3::CSRRW, rs1, (Funct12)csr));
}
void RiscVEmitter::CSRRS(RiscVReg rd, Csr csr, RiscVReg rs1) {
_assert_msg_(SupportsZicsr(), "%s instruction not supported", __func__);
_assert_msg_((u32)csr <= 0x00000FFF, "%s with invalid CSR number", __func__);
Write32(EncodeGI(Opcode32::SYSTEM, rd, Funct3::CSRRS, rs1, (Funct12)csr));
}
void RiscVEmitter::CSRRC(RiscVReg rd, Csr csr, RiscVReg rs1) {
_assert_msg_(SupportsZicsr(), "%s instruction not supported", __func__);
_assert_msg_((u32)csr <= 0x00000FFF, "%s with invalid CSR number", __func__);
Write32(EncodeGI(Opcode32::SYSTEM, rd, Funct3::CSRRC, rs1, (Funct12)csr));
}
void RiscVEmitter::CSRRWI(RiscVReg rd, Csr csr, u8 uimm5) {
_assert_msg_(SupportsZicsr(), "%s instruction not supported", __func__);
_assert_msg_((u32)csr <= 0x00000FFF, "%s with invalid CSR number", __func__);
_assert_msg_((u32)uimm5 <= 0x1F, "%s can only specify lowest 5 bits", __func__);
Write32(EncodeGI(Opcode32::SYSTEM, rd, Funct3::CSRRWI, (RiscVReg)uimm5, (Funct12)csr));
}
void RiscVEmitter::CSRRSI(RiscVReg rd, Csr csr, u8 uimm5) {
_assert_msg_(SupportsZicsr(), "%s instruction not supported", __func__);
_assert_msg_((u32)csr <= 0x00000FFF, "%s with invalid CSR number", __func__);
_assert_msg_((u32)uimm5 <= 0x1F, "%s can only set lowest 5 bits", __func__);
Write32(EncodeGI(Opcode32::SYSTEM, rd, Funct3::CSRRSI, (RiscVReg)uimm5, (Funct12)csr));
}
void RiscVEmitter::CSRRCI(RiscVReg rd, Csr csr, u8 uimm5) {
_assert_msg_(SupportsZicsr(), "%s instruction not supported", __func__);
_assert_msg_((u32)csr <= 0x00000FFF, "%s with invalid CSR number", __func__);
_assert_msg_((u32)uimm5 <= 0x1F, "%s can only clear lowest 5 bits", __func__);
Write32(EncodeGI(Opcode32::SYSTEM, rd, Funct3::CSRRCI, (RiscVReg)uimm5, (Funct12)csr));
}
};

View file

@ -90,6 +90,19 @@ enum class FMv {
D,
};
enum class Csr {
FFlags = 0x001,
FRm = 0x002,
FCsr = 0x003,
Cycle = 0xC00,
Time = 0xC01,
InstRet = 0xC02,
CycleH = 0xC80,
TimeH = 0xC81,
InstRetH = 0xC82,
};
struct FixupBranch {
FixupBranch(const u8 *p, FixupBranchType t) : ptr(p), type(t) {}
~FixupBranch();
@ -297,6 +310,28 @@ public:
void FLE(int bits, RiscVReg rd, RiscVReg rs1, RiscVReg rs2);
void FCLASS(int bits, RiscVReg rd, RiscVReg rs1);
// Control state register manipulation.
void CSRRW(RiscVReg rd, Csr csr, RiscVReg rs1);
void CSRRS(RiscVReg rd, Csr csr, RiscVReg rs1);
void CSRRC(RiscVReg rd, Csr csr, RiscVReg rs1);
void CSRRWI(RiscVReg rd, Csr csr, u8 uimm5);
void CSRRSI(RiscVReg rd, Csr csr, u8 uimm5);
void CSRRCI(RiscVReg rd, Csr csr, u8 uimm5);
void FRRM(RiscVReg rd) {
CSRRS(rd, Csr::FRm, X0);
}
void FSRM(RiscVReg rs) {
CSRRW(X0, Csr::FRm, rs);
}
void FSRMI(RiscVReg rd, Round rm) {
_assert_msg_(rm != Round::DYNAMIC, "Cannot set FRm to DYNAMIC");
CSRRWI(rd, Csr::FRm, (uint8_t)rm);
}
void FSRMI(Round rm) {
FSRMI(X0, rm);
}
private:
void SetJumpTarget(FixupBranch &branch, const void *dst);
bool BInRange(const void *src, const void *dst) const;