mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
riscv: Add encoding for Zcb.
This commit is contained in:
parent
15cb782f85
commit
e3c6add63a
2 changed files with 231 additions and 5 deletions
|
@ -27,8 +27,16 @@
|
|||
|
||||
namespace RiscVGen {
|
||||
|
||||
static inline bool SupportsCompressed() {
|
||||
return cpu_info.RiscV_C;
|
||||
static inline bool SupportsCompressed(char zcx = '\0') {
|
||||
if (!cpu_info.RiscV_C)
|
||||
return false;
|
||||
|
||||
switch (zcx) {
|
||||
// TODO: cpu_info.RiscV_Zcb
|
||||
case 'b': return false;
|
||||
case '\0': return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint8_t BitsSupported() {
|
||||
|
@ -261,6 +269,7 @@ enum class Funct2 {
|
|||
|
||||
C_SUBW = 0b00,
|
||||
C_ADDW = 0b01,
|
||||
C_MUL = 0b10,
|
||||
};
|
||||
|
||||
enum class Funct7 {
|
||||
|
@ -358,6 +367,13 @@ enum class Funct5 {
|
|||
SEXT_B = 0b00100,
|
||||
SEXT_H = 0b00101,
|
||||
ORC_B = 0b00111,
|
||||
|
||||
C_ZEXT_B = 0b11000,
|
||||
C_SEXT_B = 0b11001,
|
||||
C_ZEXT_H = 0b11010,
|
||||
C_SEXT_H = 0b11011,
|
||||
C_ZEXT_W = 0b11100,
|
||||
C_NOT = 0b11101,
|
||||
};
|
||||
|
||||
enum class Funct4 {
|
||||
|
@ -370,6 +386,10 @@ enum class Funct4 {
|
|||
enum class Funct6 {
|
||||
C_OP = 0b100011,
|
||||
C_OP_32 = 0b100111,
|
||||
C_LBU = 0b100000,
|
||||
C_LH = 0b100001,
|
||||
C_SB = 0b100010,
|
||||
C_SH = 0b100011,
|
||||
|
||||
VADD = 0b000000,
|
||||
VSUB = 0b000010,
|
||||
|
@ -895,6 +915,35 @@ static inline u16 EncodeCJ(Opcode16 op, s32 simm12, Funct3 funct3) {
|
|||
return (u16)op | (imm11_4_9_8_10_6_7_3_2_1_5 << 2) | ((u16)funct3 << 13);
|
||||
}
|
||||
|
||||
static inline u16 EncodeCLB(Opcode16 op, RiscCReg rd, u8 uimm2, RiscCReg rs1, Funct6 funct6) {
|
||||
_assert_msg_(SupportsCompressed(), "Compressed instructions unsupported");
|
||||
_assert_msg_((uimm2 & 3) == uimm2, "CLB immediate must be 2 bit: %d", uimm2);
|
||||
return (u16)op | ((u16)rd << 2) | ((u16)uimm2 << 5) | ((u16)rs1 << 7) | ((u16)funct6 << 10);
|
||||
}
|
||||
|
||||
static inline u16 EncodeCSB(Opcode16 op, RiscCReg rs2, u8 uimm2, RiscCReg rs1, Funct6 funct6) {
|
||||
_assert_msg_(SupportsCompressed(), "Compressed instructions unsupported");
|
||||
_assert_msg_((uimm2 & 3) == uimm2, "CSB immediate must be 2 bit: %d", uimm2);
|
||||
return (u16)op | ((u16)rs2 << 2) | ((u16)uimm2 << 5) | ((u16)rs1 << 7) | ((u16)funct6 << 10);
|
||||
}
|
||||
|
||||
static inline u16 EncodeCLH(Opcode16 op, RiscCReg rd, u8 uimm1, bool funct1, RiscCReg rs1, Funct6 funct6) {
|
||||
_assert_msg_(SupportsCompressed(), "Compressed instructions unsupported");
|
||||
_assert_msg_((uimm1 & 1) == uimm1, "CLH immediate must be 1 bit: %d", uimm1);
|
||||
return (u16)op | ((u16)rd << 2) | ((u16)uimm1 << 5) | ((u16)funct1 << 6) | ((u16)rs1 << 7) | ((u16)funct6 << 10);
|
||||
}
|
||||
|
||||
static inline u16 EncodeCSH(Opcode16 op, RiscCReg rs2, u8 uimm1, bool funct1, RiscCReg rs1, Funct6 funct6) {
|
||||
_assert_msg_(SupportsCompressed(), "Compressed instructions unsupported");
|
||||
_assert_msg_((uimm1 & 1) == uimm1, "CSH immediate must be 1 bit: %d", uimm1);
|
||||
return (u16)op | ((u16)rs2 << 2) | ((u16)uimm1 << 5) | ((u16)funct1 << 6) | ((u16)rs1 << 7) | ((u16)funct6 << 10);
|
||||
}
|
||||
|
||||
static inline u16 EncodeCU(Opcode16 op, Funct5 funct5, RiscCReg rd, Funct6 funct6) {
|
||||
_assert_msg_(SupportsCompressed(), "Compressed instructions unsupported");
|
||||
return (u16)op | ((u16)funct5 << 2) | ((u16)rd << 7) | ((u16)funct6 << 10);
|
||||
}
|
||||
|
||||
static inline Funct3 BitsToFunct3(int bits, bool useFloat = false, bool allowHalfMin = false) {
|
||||
int bitsSupported = useFloat ? FloatBitsSupported() : BitsSupported();
|
||||
_assert_msg_(bitsSupported >= bits, "Cannot use funct3 width %d, only have %d", bits, bitsSupported);
|
||||
|
@ -1478,6 +1527,12 @@ void RiscVEmitter::LB(RiscVReg rd, RiscVReg rs1, s32 simm12) {
|
|||
}
|
||||
|
||||
void RiscVEmitter::LH(RiscVReg rd, RiscVReg rs1, s32 simm12) {
|
||||
if (AutoCompress() && SupportsCompressed('b')) {
|
||||
if (CanCompress(rd) && CanCompress(rs1) && (simm12 & 2) == simm12) {
|
||||
C_LH(rd, rs1, simm12 & 3);
|
||||
return;
|
||||
}
|
||||
}
|
||||
Write32(EncodeGI(Opcode32::LOAD, rd, Funct3::LS_H, rs1, simm12));
|
||||
}
|
||||
|
||||
|
@ -1496,18 +1551,42 @@ void RiscVEmitter::LW(RiscVReg rd, RiscVReg rs1, s32 simm12) {
|
|||
}
|
||||
|
||||
void RiscVEmitter::LBU(RiscVReg rd, RiscVReg rs1, s32 simm12) {
|
||||
if (AutoCompress() && SupportsCompressed('b')) {
|
||||
if (CanCompress(rd) && CanCompress(rs1) && (simm12 & 3) == simm12) {
|
||||
C_LBU(rd, rs1, simm12 & 3);
|
||||
return;
|
||||
}
|
||||
}
|
||||
Write32(EncodeGI(Opcode32::LOAD, rd, Funct3::LS_BU, rs1, simm12));
|
||||
}
|
||||
|
||||
void RiscVEmitter::LHU(RiscVReg rd, RiscVReg rs1, s32 simm12) {
|
||||
if (AutoCompress() && SupportsCompressed('b')) {
|
||||
if (CanCompress(rd) && CanCompress(rs1) && (simm12 & 2) == simm12) {
|
||||
C_LHU(rd, rs1, simm12 & 3);
|
||||
return;
|
||||
}
|
||||
}
|
||||
Write32(EncodeGI(Opcode32::LOAD, rd, Funct3::LS_HU, rs1, simm12));
|
||||
}
|
||||
|
||||
void RiscVEmitter::SB(RiscVReg rs2, RiscVReg rs1, s32 simm12) {
|
||||
if (AutoCompress() && SupportsCompressed('b')) {
|
||||
if (CanCompress(rs2) && CanCompress(rs1) && (simm12 & 3) == simm12) {
|
||||
C_SB(rs2, rs1, simm12 & 3);
|
||||
return;
|
||||
}
|
||||
}
|
||||
Write32(EncodeGS(Opcode32::STORE, Funct3::LS_B, rs1, rs2, simm12));
|
||||
}
|
||||
|
||||
void RiscVEmitter::SH(RiscVReg rs2, RiscVReg rs1, s32 simm12) {
|
||||
if (AutoCompress() && SupportsCompressed('b')) {
|
||||
if (CanCompress(rs2) && CanCompress(rs1) && (simm12 & 2) == simm12) {
|
||||
C_SH(rs2, rs1, simm12 & 3);
|
||||
return;
|
||||
}
|
||||
}
|
||||
Write32(EncodeGS(Opcode32::STORE, Funct3::LS_H, rs1, rs2, simm12));
|
||||
}
|
||||
|
||||
|
@ -1563,6 +1642,12 @@ void RiscVEmitter::SLTIU(RiscVReg rd, RiscVReg rs1, s32 simm12) {
|
|||
|
||||
void RiscVEmitter::XORI(RiscVReg rd, RiscVReg rs1, s32 simm12) {
|
||||
_assert_msg_(rd != R_ZERO, "%s write to zero is a HINT", __func__);
|
||||
|
||||
if (AutoCompress() && SupportsCompressed('b') && CanCompress(rd) && rd == rs1 && simm12 == -1) {
|
||||
C_NOT(rd);
|
||||
return;
|
||||
}
|
||||
|
||||
Write32(EncodeGI(Opcode32::OP_IMM, rd, Funct3::XOR, rs1, simm12));
|
||||
}
|
||||
|
||||
|
@ -1582,9 +1667,14 @@ void RiscVEmitter::ORI(RiscVReg rd, RiscVReg rs1, s32 simm12) {
|
|||
void RiscVEmitter::ANDI(RiscVReg rd, RiscVReg rs1, s32 simm12) {
|
||||
_assert_msg_(rd != R_ZERO, "%s write to zero is a HINT", __func__);
|
||||
|
||||
if (AutoCompress() && CanCompress(rd) && rd == rs1 && SignReduce32(simm12, 6) == simm12) {
|
||||
C_ANDI(rd, (s8)simm12);
|
||||
return;
|
||||
if (AutoCompress() && CanCompress(rd) && rd == rs1) {
|
||||
if (SignReduce32(simm12, 6) == simm12) {
|
||||
C_ANDI(rd, (s8)simm12);
|
||||
return;
|
||||
} else if (SupportsCompressed('b') && simm12 == 0xFF) {
|
||||
C_ZEXT_B(rd);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Write32(EncodeGI(Opcode32::OP_IMM, rd, Funct3::AND, rs1, simm12));
|
||||
|
@ -1903,6 +1993,17 @@ void RiscVEmitter::MUL(RiscVReg rd, RiscVReg rs1, RiscVReg rs2) {
|
|||
_assert_msg_(SupportsMulDiv(true), "%s instruction unsupported without M/Zmmul", __func__);
|
||||
// Not explicitly a HINT, but seems sensible to restrict just in case.
|
||||
_assert_msg_(rd != R_ZERO, "%s write to zero", __func__);
|
||||
|
||||
if (AutoCompress() && SupportsCompressed('b') && CanCompress(rd)) {
|
||||
if (rd == rs1 && CanCompress(rs2)) {
|
||||
C_MUL(rd, rs2);
|
||||
return;
|
||||
} else if (rd == rs2 && CanCompress(rs1)) {
|
||||
C_MUL(rd, rs1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Write32(EncodeGR(Opcode32::OP, rd, Funct3::MUL, rs1, rs2, Funct7::MULDIV));
|
||||
}
|
||||
|
||||
|
@ -3881,6 +3982,12 @@ void RiscVEmitter::ADD_UW(RiscVReg rd, RiscVReg rs1, RiscVReg rs2) {
|
|||
|
||||
_assert_msg_(rd != R_ZERO, "%s should avoid write to zero", __func__);
|
||||
_assert_msg_(SupportsBitmanip('a'), "%s instruction unsupported without B", __func__);
|
||||
|
||||
if (AutoCompress() && SupportsCompressed('b') && CanCompress(rd) && rd == rs1 && rs2 == R_ZERO) {
|
||||
C_ZEXT_W(rd);
|
||||
return;
|
||||
}
|
||||
|
||||
Write32(EncodeGR(Opcode32::OP_32, rd, Funct3::ADD, rs1, rs2, Funct7::ADDUW_ZEXT));
|
||||
}
|
||||
|
||||
|
@ -4024,18 +4131,36 @@ void RiscVEmitter::MINU(RiscVReg rd, RiscVReg rs1, RiscVReg rs2) {
|
|||
void RiscVEmitter::SEXT_B(RiscVReg rd, RiscVReg rs) {
|
||||
_assert_msg_(rd != R_ZERO, "%s should avoid write to zero", __func__);
|
||||
_assert_msg_(SupportsBitmanip('b'), "%s instruction unsupported without B", __func__);
|
||||
|
||||
if (AutoCompress() && SupportsCompressed('b') && CanCompress(rd) && rd == rs) {
|
||||
C_SEXT_B(rd);
|
||||
return;
|
||||
}
|
||||
|
||||
Write32(EncodeGR(Opcode32::OP_IMM, rd, Funct3::COUNT_SEXT_ROL, rs, Funct5::SEXT_B, Funct7::COUNT_SEXT_ROT));
|
||||
}
|
||||
|
||||
void RiscVEmitter::SEXT_H(RiscVReg rd, RiscVReg rs) {
|
||||
_assert_msg_(rd != R_ZERO, "%s should avoid write to zero", __func__);
|
||||
_assert_msg_(SupportsBitmanip('b'), "%s instruction unsupported without B", __func__);
|
||||
|
||||
if (AutoCompress() && SupportsCompressed('b') && CanCompress(rd) && rd == rs) {
|
||||
C_SEXT_H(rd);
|
||||
return;
|
||||
}
|
||||
|
||||
Write32(EncodeGR(Opcode32::OP_IMM, rd, Funct3::COUNT_SEXT_ROL, rs, Funct5::SEXT_H, Funct7::COUNT_SEXT_ROT));
|
||||
}
|
||||
|
||||
void RiscVEmitter::ZEXT_H(RiscVReg rd, RiscVReg rs) {
|
||||
_assert_msg_(rd != R_ZERO, "%s should avoid write to zero", __func__);
|
||||
_assert_msg_(SupportsBitmanip('b'), "%s instruction unsupported without B", __func__);
|
||||
|
||||
if (AutoCompress() && SupportsCompressed('b') && CanCompress(rd) && rd == rs) {
|
||||
C_ZEXT_H(rd);
|
||||
return;
|
||||
}
|
||||
|
||||
if (BitsSupported() == 32)
|
||||
Write32(EncodeGR(Opcode32::OP, rd, Funct3::ZEXT, rs, R_ZERO, Funct7::ADDUW_ZEXT));
|
||||
else
|
||||
|
@ -4512,6 +4637,88 @@ void RiscVEmitter::C_SDSP(RiscVReg rs2, u32 uimm9) {
|
|||
Write16(EncodeCSS(Opcode16::C2, rs2, imm5_4_3_8_7_6, Funct3::C_SDSP));
|
||||
}
|
||||
|
||||
void RiscVEmitter::C_LBU(RiscVReg rd, RiscVReg rs1, u8 uimm2) {
|
||||
_assert_msg_(SupportsCompressed('b'), "Zcb compressed instructions unsupported");
|
||||
_assert_msg_(IsGPR(rd) && IsGPR(rs1), "%s must use GPRs", __func__);
|
||||
_assert_msg_((uimm2 & 3) == uimm2, "%s offset must be 0-3", __func__);
|
||||
Write16(EncodeCLB(Opcode16::C0, CompressReg(rd), uimm2, CompressReg(rs1), Funct6::C_LBU));
|
||||
}
|
||||
|
||||
void RiscVEmitter::C_LHU(RiscVReg rd, RiscVReg rs1, u8 uimm2) {
|
||||
_assert_msg_(SupportsCompressed('b'), "Zcb compressed instructions unsupported");
|
||||
_assert_msg_(IsGPR(rd) && IsGPR(rs1), "%s must use GPRs", __func__);
|
||||
_assert_msg_((uimm2 & 2) == uimm2, "%s offset must be 0 or 2", __func__);
|
||||
Write16(EncodeCLH(Opcode16::C0, CompressReg(rd), uimm2 >> 1, false, CompressReg(rs1), Funct6::C_LH));
|
||||
}
|
||||
|
||||
void RiscVEmitter::C_LH(RiscVReg rd, RiscVReg rs1, u8 uimm2) {
|
||||
_assert_msg_(SupportsCompressed('b'), "Zcb compressed instructions unsupported");
|
||||
_assert_msg_(IsGPR(rd) && IsGPR(rs1), "%s must use GPRs", __func__);
|
||||
_assert_msg_((uimm2 & 2) == uimm2, "%s offset must be 0 or 2", __func__);
|
||||
Write16(EncodeCLH(Opcode16::C0, CompressReg(rd), uimm2 >> 1, true, CompressReg(rs1), Funct6::C_LH));
|
||||
}
|
||||
|
||||
void RiscVEmitter::C_SB(RiscVReg rs2, RiscVReg rs1, u8 uimm2) {
|
||||
_assert_msg_(SupportsCompressed('b'), "Zcb compressed instructions unsupported");
|
||||
_assert_msg_(IsGPR(rs2) && IsGPR(rs1), "%s must use GPRs", __func__);
|
||||
_assert_msg_((uimm2 & 3) == uimm2, "%s offset must be 0-3", __func__);
|
||||
Write16(EncodeCSB(Opcode16::C0, CompressReg(rs2), uimm2, CompressReg(rs1), Funct6::C_SB));
|
||||
}
|
||||
|
||||
void RiscVEmitter::C_SH(RiscVReg rs2, RiscVReg rs1, u8 uimm2) {
|
||||
_assert_msg_(SupportsCompressed('b'), "Zcb compressed instructions unsupported");
|
||||
_assert_msg_(IsGPR(rs2) && IsGPR(rs1), "%s must use GPRs", __func__);
|
||||
_assert_msg_((uimm2 & 2) == uimm2, "%s offset must be 0 or 2", __func__);
|
||||
Write16(EncodeCSH(Opcode16::C0, CompressReg(rs2), uimm2 >> 1, false, CompressReg(rs1), Funct6::C_SH));
|
||||
}
|
||||
|
||||
void RiscVEmitter::C_ZEXT_B(RiscVReg rd) {
|
||||
_assert_msg_(SupportsCompressed('b'), "Zcb compressed instructions unsupported");
|
||||
_assert_msg_(IsGPR(rd), "%s must use GPRs", __func__);
|
||||
Write16(EncodeCU(Opcode16::C1, Funct5::C_ZEXT_B, CompressReg(rd), Funct6::C_OP_32));
|
||||
}
|
||||
|
||||
void RiscVEmitter::C_SEXT_B(RiscVReg rd) {
|
||||
_assert_msg_(SupportsCompressed('b'), "Zcb compressed instructions unsupported");
|
||||
_assert_msg_(SupportsBitmanip('b'), "Zbb bitmanip instructions unsupported");
|
||||
_assert_msg_(IsGPR(rd), "%s must use GPRs", __func__);
|
||||
Write16(EncodeCU(Opcode16::C1, Funct5::C_SEXT_B, CompressReg(rd), Funct6::C_OP_32));
|
||||
}
|
||||
|
||||
void RiscVEmitter::C_ZEXT_H(RiscVReg rd) {
|
||||
_assert_msg_(SupportsCompressed('b'), "Zcb compressed instructions unsupported");
|
||||
_assert_msg_(SupportsBitmanip('b'), "Zbb bitmanip instructions unsupported");
|
||||
_assert_msg_(IsGPR(rd), "%s must use GPRs", __func__);
|
||||
Write16(EncodeCU(Opcode16::C1, Funct5::C_ZEXT_H, CompressReg(rd), Funct6::C_OP_32));
|
||||
}
|
||||
|
||||
void RiscVEmitter::C_SEXT_H(RiscVReg rd) {
|
||||
_assert_msg_(SupportsCompressed('b'), "Zcb compressed instructions unsupported");
|
||||
_assert_msg_(SupportsBitmanip('b'), "Zbb bitmanip instructions unsupported");
|
||||
_assert_msg_(IsGPR(rd), "%s must use GPRs", __func__);
|
||||
Write16(EncodeCU(Opcode16::C1, Funct5::C_SEXT_H, CompressReg(rd), Funct6::C_OP_32));
|
||||
}
|
||||
|
||||
void RiscVEmitter::C_ZEXT_W(RiscVReg rd) {
|
||||
_assert_msg_(SupportsCompressed('b'), "Zcb compressed instructions unsupported");
|
||||
_assert_msg_(SupportsBitmanip('a'), "Zba bitmanip instructions unsupported");
|
||||
_assert_msg_(IsGPR(rd), "%s must use GPRs", __func__);
|
||||
Write16(EncodeCU(Opcode16::C1, Funct5::C_ZEXT_W, CompressReg(rd), Funct6::C_OP_32));
|
||||
}
|
||||
|
||||
void RiscVEmitter::C_NOT(RiscVReg rd) {
|
||||
_assert_msg_(SupportsCompressed('b'), "Zcb compressed instructions unsupported");
|
||||
_assert_msg_(IsGPR(rd), "%s must use GPRs", __func__);
|
||||
Write16(EncodeCU(Opcode16::C1, Funct5::C_NOT, CompressReg(rd), Funct6::C_OP_32));
|
||||
}
|
||||
|
||||
void RiscVEmitter::C_MUL(RiscVReg rd, RiscVReg rs2) {
|
||||
_assert_msg_(SupportsCompressed('b'), "Zcb compressed instructions unsupported");
|
||||
_assert_msg_(SupportsMulDiv(true), "%s instruction unsupported without M/Zmmul", __func__);
|
||||
_assert_msg_(IsGPR(rd), "%s must use GPRs", __func__);
|
||||
Write16(EncodeCA(Opcode16::C1, CompressReg(rs2), Funct2::C_MUL, CompressReg(rd), Funct6::C_OP_32));
|
||||
}
|
||||
|
||||
void RiscVCodeBlock::PoisonMemory(int offset) {
|
||||
// So we can adjust region to writable space. Might be zero.
|
||||
ptrdiff_t writable = writable_ - code_;
|
||||
|
|
|
@ -938,6 +938,9 @@ public:
|
|||
void SEXT_W(RiscVReg rd, RiscVReg rs) {
|
||||
ADDIW(rd, rs, 0);
|
||||
}
|
||||
void ZEXT_B(RiscVReg rd, RiscVReg rs) {
|
||||
ANDI(rd, rs, 0xFF);
|
||||
}
|
||||
void ZEXT_H(RiscVReg rd, RiscVReg rs);
|
||||
void ZEXT_W(RiscVReg rd, RiscVReg rs) {
|
||||
ADD_UW(rd, rs, R_ZERO);
|
||||
|
@ -1012,6 +1015,22 @@ public:
|
|||
void C_FSWSP(RiscVReg rs2, u8 uimm8);
|
||||
void C_SDSP(RiscVReg rs2, u32 uimm9);
|
||||
|
||||
void C_LBU(RiscVReg rd, RiscVReg rs1, u8 uimm2);
|
||||
void C_LHU(RiscVReg rd, RiscVReg rs1, u8 uimm2);
|
||||
void C_LH(RiscVReg rd, RiscVReg rs1, u8 uimm2);
|
||||
void C_SB(RiscVReg rs2, RiscVReg rs1, u8 uimm2);
|
||||
void C_SH(RiscVReg rs2, RiscVReg rs1, u8 uimm2);
|
||||
void C_ZEXT_B(RiscVReg rd);
|
||||
void C_SEXT_B(RiscVReg rd);
|
||||
void C_ZEXT_H(RiscVReg rd);
|
||||
void C_SEXT_H(RiscVReg rd);
|
||||
void C_ZEXT_W(RiscVReg rd);
|
||||
void C_SEXT_W(RiscVReg rd) {
|
||||
C_ADDIW(rd, 0);
|
||||
}
|
||||
void C_NOT(RiscVReg rd);
|
||||
void C_MUL(RiscVReg rd, RiscVReg rs2);
|
||||
|
||||
bool CBInRange(const void *func) const;
|
||||
bool CJInRange(const void *func) const;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue