mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-25 07:30:15 +00:00
fixup! BitUtil: Correct error messages, independent impl of Bit, correct SignExtend logic
This commit is contained in:
parent
9abe861152
commit
208795b885
@ -13,29 +13,31 @@ constexpr size_t BitSize() {
|
|||||||
return sizeof(T) * CHAR_BIT;
|
return sizeof(T) * CHAR_BIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extract bits [begin_bit, end_bit] inclusive from val of type T.
|
/// Extract bits [begin_bit, end_bit] inclusive from value of type T.
|
||||||
template<size_t begin_bit, size_t end_bit, typename T>
|
template<size_t begin_bit, size_t end_bit, typename T>
|
||||||
constexpr T Bits(const T value) {
|
constexpr T Bits(const T value) {
|
||||||
static_assert(begin_bit <= end_bit, "bit range must begin before it ends");
|
static_assert(begin_bit < end_bit, "invalid bit range (position of beginning bit cannot be greater than that of end bit)");
|
||||||
static_assert(begin_bit < BitSize<T>(), "begin_bit must be smaller than size of T");
|
static_assert(begin_bit < BitSize<T>(), "begin_bit must be smaller than size of T");
|
||||||
static_assert(end_bit < BitSize<T>(), "begin_bit must be smaller than size of T");
|
static_assert(end_bit < BitSize<T>(), "begin_bit must be smaller than size of T");
|
||||||
|
|
||||||
return (value >> begin_bit) & ((1 << (end_bit - begin_bit + 1)) - 1);
|
return (value >> begin_bit) & ((1 << (end_bit - begin_bit + 1)) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extracts a single bit at bit_position from val of type T.
|
/// Extracts a single bit at bit_position from value of type T.
|
||||||
template<size_t bit_position, typename T>
|
template<size_t bit_position, typename T>
|
||||||
constexpr T Bit(const T value) {
|
constexpr T Bit(const T value) {
|
||||||
return Bits<bit_position, bit_position, T>(value);
|
static_assert(bit_position < BitSize<T>(), "bit_position must be smaller than size of T");
|
||||||
|
|
||||||
|
return (value >> bit_position) & 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sign-extends a val that has NBits bits to the full bitwidth of type T.
|
/// Sign-extends a value that has NBits bits to the full bitwidth of type T.
|
||||||
template<size_t NBits, typename T>
|
template<size_t NBits, typename T>
|
||||||
inline T SignExtend(const T value) {
|
inline T SignExtend(const T value) {
|
||||||
static_assert(NBits <= BitSize<T>(), "NBits larger that bitsize of T");
|
static_assert(NBits <= BitSize<T>(), "NBits larger than bitsize of T");
|
||||||
|
|
||||||
constexpr T mask = static_cast<T>(1ULL << NBits) - 1;
|
constexpr T mask = static_cast<T>(1ULL << NBits) - 1;
|
||||||
const T signbit = (value >> NBits) & 1;
|
const T signbit = Bit<NBits - 1>(value);
|
||||||
if (signbit != 0) {
|
if (signbit != 0) {
|
||||||
return value | ~mask;
|
return value | ~mask;
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,7 @@ ThumbMatcher MakeMatcher(const char* const str, std::function<void(Visitor* v, u
|
|||||||
return { mask, expect, fn };
|
return { mask, expect, fn };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using BitUtil::Bit;
|
||||||
using BitUtil::Bits;
|
using BitUtil::Bits;
|
||||||
|
|
||||||
static const std::array<ThumbInstruction, 27> thumb_instruction_table = { {
|
static const std::array<ThumbInstruction, 27> thumb_instruction_table = { {
|
||||||
@ -66,7 +67,7 @@ static const std::array<ThumbInstruction, 27> thumb_instruction_table = { {
|
|||||||
}
|
}
|
||||||
})},
|
})},
|
||||||
{ "ADD/SUB_reg", MakeMatcher("000110oxxxxxxxxx", [](Visitor* v, u16 instruction) {
|
{ "ADD/SUB_reg", MakeMatcher("000110oxxxxxxxxx", [](Visitor* v, u16 instruction) {
|
||||||
u32 opcode = Bits<9, 9>(instruction);
|
u32 opcode = Bit<9>(instruction);
|
||||||
Register Rm = static_cast<Register>(Bits<6, 8>(instruction));
|
Register Rm = static_cast<Register>(Bits<6, 8>(instruction));
|
||||||
Register Rn = static_cast<Register>(Bits<3, 5>(instruction));
|
Register Rn = static_cast<Register>(Bits<3, 5>(instruction));
|
||||||
Register Rd = static_cast<Register>(Bits<0, 2>(instruction));
|
Register Rd = static_cast<Register>(Bits<0, 2>(instruction));
|
||||||
@ -82,7 +83,7 @@ static const std::array<ThumbInstruction, 27> thumb_instruction_table = { {
|
|||||||
}
|
}
|
||||||
})},
|
})},
|
||||||
{ "ADD/SUB_imm", MakeMatcher("000111oxxxxxxxxx", [](Visitor* v, u16 instruction) {
|
{ "ADD/SUB_imm", MakeMatcher("000111oxxxxxxxxx", [](Visitor* v, u16 instruction) {
|
||||||
u32 opcode = Bits<9, 9>(instruction);
|
u32 opcode = Bit<9>(instruction);
|
||||||
u32 imm3 = Bits<6, 8>(instruction);
|
u32 imm3 = Bits<6, 8>(instruction);
|
||||||
Register Rn = static_cast<Register>(Bits<3, 5>(instruction));
|
Register Rn = static_cast<Register>(Bits<3, 5>(instruction));
|
||||||
Register Rd = static_cast<Register>(Bits<0, 2>(instruction));
|
Register Rd = static_cast<Register>(Bits<0, 2>(instruction));
|
||||||
@ -178,7 +179,7 @@ static const std::array<ThumbInstruction, 27> thumb_instruction_table = { {
|
|||||||
{ "special data processing", MakeMatcher("010001ooxxxxxxxx", [](Visitor* v, u16 instruction) {
|
{ "special data processing", MakeMatcher("010001ooxxxxxxxx", [](Visitor* v, u16 instruction) {
|
||||||
u32 opcode = Bits<8, 9>(instruction);
|
u32 opcode = Bits<8, 9>(instruction);
|
||||||
Register Rm = static_cast<Register>(Bits<3, 6>(instruction));
|
Register Rm = static_cast<Register>(Bits<3, 6>(instruction));
|
||||||
Register Rd = static_cast<Register>(Bits<0, 2>(instruction) | (Bits<7, 7>(instruction) << 3));
|
Register Rd = static_cast<Register>(Bits<0, 2>(instruction) | (Bit<7>(instruction) << 3));
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case 0: // ADD Rd, Rm
|
case 0: // ADD Rd, Rm
|
||||||
v->ADD_reg(Cond::AL, /*S=*/false, Rd, Rd, 0, ShiftType::LSL, Rm);
|
v->ADD_reg(Cond::AL, /*S=*/false, Rd, Rd, 0, ShiftType::LSL, Rm);
|
||||||
@ -194,7 +195,7 @@ static const std::array<ThumbInstruction, 27> thumb_instruction_table = { {
|
|||||||
}
|
}
|
||||||
})},
|
})},
|
||||||
{ "BLX/BX", MakeMatcher("01000111xxxxx000", [](Visitor* v, u16 instruction) {
|
{ "BLX/BX", MakeMatcher("01000111xxxxx000", [](Visitor* v, u16 instruction) {
|
||||||
bool L = Bits<7, 7>(instruction);
|
bool L = Bit<7>(instruction);
|
||||||
Register Rm = static_cast<Register>(Bits<3, 6>(instruction));
|
Register Rm = static_cast<Register>(Bits<3, 6>(instruction));
|
||||||
if (!L) { // BX Rm
|
if (!L) { // BX Rm
|
||||||
v->BX(Cond::AL, Rm);
|
v->BX(Cond::AL, Rm);
|
||||||
@ -265,7 +266,7 @@ static const std::array<ThumbInstruction, 27> thumb_instruction_table = { {
|
|||||||
}
|
}
|
||||||
})},
|
})},
|
||||||
{ "STRH/LDRH_imm", MakeMatcher("1000xxxxxxxxxxxx", [](Visitor* v, u16 instruction) {
|
{ "STRH/LDRH_imm", MakeMatcher("1000xxxxxxxxxxxx", [](Visitor* v, u16 instruction) {
|
||||||
bool L = Bits<11, 11>(instruction);
|
bool L = Bit<11>(instruction);
|
||||||
u32 offset = Bits<6, 10>(instruction);
|
u32 offset = Bits<6, 10>(instruction);
|
||||||
Register Rn = static_cast<Register>(Bits<3, 5>(instruction));
|
Register Rn = static_cast<Register>(Bits<3, 5>(instruction));
|
||||||
Register Rd = static_cast<Register>(Bits<0, 2>(instruction));
|
Register Rd = static_cast<Register>(Bits<0, 2>(instruction));
|
||||||
@ -276,7 +277,7 @@ static const std::array<ThumbInstruction, 27> thumb_instruction_table = { {
|
|||||||
}
|
}
|
||||||
})},
|
})},
|
||||||
{ "load/store stack", MakeMatcher("1001xxxxxxxxxxxx", [](Visitor* v, u16 instruction) {
|
{ "load/store stack", MakeMatcher("1001xxxxxxxxxxxx", [](Visitor* v, u16 instruction) {
|
||||||
bool L = Bits<11, 11>(instruction);
|
bool L = Bit<11>(instruction);
|
||||||
Register Rd = static_cast<Register>(Bits<8, 10>(instruction));
|
Register Rd = static_cast<Register>(Bits<8, 10>(instruction));
|
||||||
u32 offset = Bits<0, 7>(instruction);
|
u32 offset = Bits<0, 7>(instruction);
|
||||||
if (!L) { // STR Rd, [SP, #offset]
|
if (!L) { // STR Rd, [SP, #offset]
|
||||||
@ -287,14 +288,14 @@ static const std::array<ThumbInstruction, 27> thumb_instruction_table = { {
|
|||||||
})},
|
})},
|
||||||
{ "add to sp/pc", MakeMatcher("1010oxxxxxxxxxxx", [](Visitor* v, u16 instruction) {
|
{ "add to sp/pc", MakeMatcher("1010oxxxxxxxxxxx", [](Visitor* v, u16 instruction) {
|
||||||
// ADD Rd, PC/SP, #imm8
|
// ADD Rd, PC/SP, #imm8
|
||||||
Register Rn = Bits<11, 11>(instruction) ? Register::SP : Register::PC;
|
Register Rn = Bit<11>(instruction) ? Register::SP : Register::PC;
|
||||||
Register Rd = static_cast<Register>(Bits<8, 10>(instruction));
|
Register Rd = static_cast<Register>(Bits<8, 10>(instruction));
|
||||||
u32 imm8 = Bits<0, 7>(instruction);
|
u32 imm8 = Bits<0, 7>(instruction);
|
||||||
v->ADD_imm(Cond::AL, /*S=*/false, Rn, Rd, 0xF, imm8);
|
v->ADD_imm(Cond::AL, /*S=*/false, Rn, Rd, 0xF, imm8);
|
||||||
})},
|
})},
|
||||||
{ "adjust stack ptr", MakeMatcher("10110000oxxxxxxx", [](Visitor* v, u16 instruction) {
|
{ "adjust stack ptr", MakeMatcher("10110000oxxxxxxx", [](Visitor* v, u16 instruction) {
|
||||||
// SUB SP, SP, #<imm7*4>
|
// SUB SP, SP, #<imm7*4>
|
||||||
u32 opc = Bits<7, 7>(instruction);
|
u32 opc = Bit<7>(instruction);
|
||||||
u32 imm7 = Bits<0, 6>(instruction);
|
u32 imm7 = Bits<0, 6>(instruction);
|
||||||
switch (opc) {
|
switch (opc) {
|
||||||
case 0:
|
case 0:
|
||||||
@ -329,8 +330,8 @@ static const std::array<ThumbInstruction, 27> thumb_instruction_table = { {
|
|||||||
}
|
}
|
||||||
})},
|
})},
|
||||||
{ "PUSH/POP_reglist", MakeMatcher("1011x10xxxxxxxxx", [](Visitor* v, u16 instruction) {
|
{ "PUSH/POP_reglist", MakeMatcher("1011x10xxxxxxxxx", [](Visitor* v, u16 instruction) {
|
||||||
bool L = Bits<11, 11>(instruction);
|
bool L = Bit<11>(instruction);
|
||||||
u32 R = Bits<8, 8>(instruction);
|
u32 R = Bit<8>(instruction);
|
||||||
u32 reglist = Bits<0, 7>(instruction);
|
u32 reglist = Bits<0, 7>(instruction);
|
||||||
if (!L) { // PUSH {reglist, <R>=LR}
|
if (!L) { // PUSH {reglist, <R>=LR}
|
||||||
reglist |= R << 14;
|
reglist |= R << 14;
|
||||||
@ -343,14 +344,14 @@ static const std::array<ThumbInstruction, 27> thumb_instruction_table = { {
|
|||||||
}
|
}
|
||||||
})},
|
})},
|
||||||
{ "SETEND", MakeMatcher("101101100101x000", [](Visitor* v, u16 instruction) {
|
{ "SETEND", MakeMatcher("101101100101x000", [](Visitor* v, u16 instruction) {
|
||||||
bool E = Bits<3, 3>(instruction);
|
u16 E = Bit<3>(instruction);
|
||||||
v->SETEND(E);
|
v->SETEND(E);
|
||||||
})},
|
})},
|
||||||
{ "change processor state", MakeMatcher("10110110011x0xxx", [](Visitor* v, u16 instruction) {
|
{ "change processor state", MakeMatcher("10110110011x0xxx", [](Visitor* v, u16 instruction) {
|
||||||
bool imod = Bits<4, 4>(instruction);
|
u16 imod = Bit<4>(instruction);
|
||||||
bool A = Bits<2, 2>(instruction);
|
u16 A = Bit<2>(instruction);
|
||||||
bool I = Bits<1, 1>(instruction);
|
u16 I = Bit<1>(instruction);
|
||||||
bool F = Bits<0, 0>(instruction);
|
u16 F = Bit<0>(instruction);
|
||||||
v->CPS();
|
v->CPS();
|
||||||
})},
|
})},
|
||||||
{ "reverse bytes", MakeMatcher("10111010ooxxxxxx", [](Visitor* v, u16 instruction) {
|
{ "reverse bytes", MakeMatcher("10111010ooxxxxxx", [](Visitor* v, u16 instruction) {
|
||||||
@ -380,7 +381,7 @@ static const std::array<ThumbInstruction, 27> thumb_instruction_table = { {
|
|||||||
v->BKPT(Cond::AL, imm8 >> 4, imm8 & 0xF);
|
v->BKPT(Cond::AL, imm8 >> 4, imm8 & 0xF);
|
||||||
})},
|
})},
|
||||||
{ "STMIA/LDMIA", MakeMatcher("1100xxxxxxxxxxxx", [](Visitor* v, u16 instruction) {
|
{ "STMIA/LDMIA", MakeMatcher("1100xxxxxxxxxxxx", [](Visitor* v, u16 instruction) {
|
||||||
bool L = Bits<11, 11>(instruction);
|
bool L = Bit<11>(instruction);
|
||||||
Register Rn = static_cast<Register>(Bits<8, 10>(instruction));
|
Register Rn = static_cast<Register>(Bits<8, 10>(instruction));
|
||||||
u32 reglist = Bits<0, 7>(instruction);
|
u32 reglist = Bits<0, 7>(instruction);
|
||||||
if (!L) { // STMIA Rn!, { reglist }
|
if (!L) { // STMIA Rn!, { reglist }
|
||||||
|
@ -24,10 +24,11 @@ TEST_CASE("Fuzz ARM branch instructions", "[JitX64]") {
|
|||||||
auto instruction_select = [&]() -> u32 {
|
auto instruction_select = [&]() -> u32 {
|
||||||
size_t inst_index = RandInt<size_t>(0, instructions.size() - 1);
|
size_t inst_index = RandInt<size_t>(0, instructions.size() - 1);
|
||||||
|
|
||||||
u32 random = RandInt<u32>(0, 0xFFFFFFF);
|
u32 cond = RandInt<u32>(0, 0xE);
|
||||||
|
u32 random = RandInt<u32>(0, 0xFFFFFF);
|
||||||
u32 Rm = RandInt<u32>(0, 14);
|
u32 Rm = RandInt<u32>(0, 14);
|
||||||
|
|
||||||
u32 assemble_randoms = (random << 4) | Rm;
|
u32 assemble_randoms = (cond << 28) | (random << 4) | Rm;
|
||||||
|
|
||||||
return instructions[inst_index].first | (assemble_randoms & (~instructions[inst_index].second));
|
return instructions[inst_index].first | (assemble_randoms & (~instructions[inst_index].second));
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user