mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 22:06:59 +01:00
Emulate register-form SSE4a EXTRQ
This commit is contained in:
@@ -546,7 +546,11 @@ static bool TryEmulateSse4a(Context& context) {
|
|||||||
if ((rip[offset] & 0xf0u) == 0x40u) {
|
if ((rip[offset] & 0xf0u) == 0x40u) {
|
||||||
rex = rip[offset++];
|
rex = rip[offset++];
|
||||||
}
|
}
|
||||||
if (rip[offset] != 0x0f || rip[offset + 1] != 0x78) {
|
if (rip[offset] != 0x0f) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const bool register_extract = prefix == 0x66 && rip[offset + 1] == 0x79;
|
||||||
|
if (rip[offset + 1] != 0x78 && !register_extract) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -555,14 +559,12 @@ static bool TryEmulateSse4a(Context& context) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint8_t reg = ((modrm >> 3u) & 0x07u) | ((rex & 0x04u) << 1u);
|
const uint8_t reg = ((modrm >> 3u) & 0x07u) | ((rex & 0x04u) << 1u);
|
||||||
const uint8_t rm = (modrm & 0x07u) | ((rex & 0x01u) << 3u);
|
const uint8_t rm = (modrm & 0x07u) | ((rex & 0x01u) << 3u);
|
||||||
const uint8_t length = rip[offset + 3];
|
|
||||||
const uint8_t index = rip[offset + 4];
|
|
||||||
|
|
||||||
// AMD SSE4a immediate-form EXTRQ/INSERTQ.
|
// Immediate EXTRQ encodes its destination in r/m; the two-register form uses reg.
|
||||||
uint8_t dest_index = reg;
|
uint8_t dest_index = reg;
|
||||||
if (prefix == 0x66) {
|
if (prefix == 0x66 && !register_extract) {
|
||||||
dest_index = rm;
|
dest_index = rm;
|
||||||
}
|
}
|
||||||
auto* dest_xmm = context.Xmm(dest_index);
|
auto* dest_xmm = context.Xmm(dest_index);
|
||||||
@@ -574,6 +576,17 @@ static bool TryEmulateSse4a(Context& context) {
|
|||||||
uint64_t source = 0;
|
uint64_t source = 0;
|
||||||
std::memcpy(dest, dest_xmm, sizeof(dest));
|
std::memcpy(dest, dest_xmm, sizeof(dest));
|
||||||
std::memcpy(&source, src_xmm, sizeof(source));
|
std::memcpy(&source, src_xmm, sizeof(source));
|
||||||
|
uint8_t length = 0;
|
||||||
|
uint8_t index = 0;
|
||||||
|
size_t instruction_length = offset + 3;
|
||||||
|
if (register_extract) {
|
||||||
|
length = static_cast<uint8_t>(source);
|
||||||
|
index = static_cast<uint8_t>(source >> 8u);
|
||||||
|
} else {
|
||||||
|
length = rip[offset + 3];
|
||||||
|
index = rip[offset + 4];
|
||||||
|
instruction_length += 2;
|
||||||
|
}
|
||||||
if (prefix == 0x66) {
|
if (prefix == 0x66) {
|
||||||
dest[0] = ExtractBitField(dest[0], length, index);
|
dest[0] = ExtractBitField(dest[0], length, index);
|
||||||
dest[1] = 0;
|
dest[1] = 0;
|
||||||
@@ -581,7 +594,7 @@ static bool TryEmulateSse4a(Context& context) {
|
|||||||
dest[0] = InsertBitField(dest[0], source, length, index);
|
dest[0] = InsertBitField(dest[0], source, length, index);
|
||||||
}
|
}
|
||||||
std::memcpy(dest_xmm, dest, sizeof(dest));
|
std::memcpy(dest_xmm, dest, sizeof(dest));
|
||||||
context.Advance(offset + 5);
|
context.Advance(instruction_length);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2795,6 +2795,27 @@ void TestPackedReciprocalSquareRoot() {
|
|||||||
emulate({0x66, 0x41, 0x0f, 0x78, 0xc0, 8, 4}, 7); // extrq xmm8, 8, 4
|
emulate({0x66, 0x41, 0x0f, 0x78, 0xc0, 8, 4}, 7); // extrq xmm8, 8, 4
|
||||||
Check(test, fpstate._xmm[8].element[0] == 0x23 && fpstate._xmm[8].element[2] == 0,
|
Check(test, fpstate._xmm[8].element[0] == 0x23 && fpstate._xmm[8].element[2] == 0,
|
||||||
"SSE4a extraction lost its extended register or upper-half semantics");
|
"SSE4a extraction lost its extended register or upper-half semantics");
|
||||||
|
fpstate._xmm[1].element[0] = 0x1234;
|
||||||
|
fpstate._xmm[8].element[0] = 0xffffc4c8;
|
||||||
|
emulate({0x66, 0x41, 0x0f, 0x79, 0xc8}, 5); // observed fault: extrq xmm1, xmm8
|
||||||
|
Check(test, fpstate._xmm[1].element[0] == 0x23 && fpstate._xmm[8].element[0] == 0xffffc4c8,
|
||||||
|
"register EXTRQ lost its source controls, ignored bits, or separate destination");
|
||||||
|
fpstate._xmm[11].element[0] = 0x89abcdef;
|
||||||
|
fpstate._xmm[11].element[1] = 0x01234567;
|
||||||
|
fpstate._xmm[0].element[0] = 0x2010;
|
||||||
|
emulate({0x66, 0x44, 0x0f, 0x79, 0xd8}, 5); // extrq xmm11, xmm0
|
||||||
|
Check(test, fpstate._xmm[11].element[0] == 0x4567 && fpstate._xmm[11].element[1] == 0,
|
||||||
|
"register EXTRQ lost its extended destination or 64-bit extraction");
|
||||||
|
fpstate._xmm[8].element[0] = 0x89abcdef;
|
||||||
|
fpstate._xmm[8].element[1] = 0x01234567;
|
||||||
|
fpstate._xmm[9].element[0] = 0;
|
||||||
|
emulate({0x66, 0x45, 0x0f, 0x79, 0xc1}, 5); // extrq xmm8, xmm9
|
||||||
|
Check(test, fpstate._xmm[8].element[0] == 0x89abcdef && fpstate._xmm[8].element[1] == 0x01234567,
|
||||||
|
"register EXTRQ did not interpret zero length as 64 bits");
|
||||||
|
fpstate._xmm[3].element[0] = 0xab0408;
|
||||||
|
emulate({0x66, 0x0f, 0x79, 0xdb}, 4); // extrq xmm3, xmm3
|
||||||
|
Check(test, fpstate._xmm[3].element[0] == 0x40,
|
||||||
|
"register EXTRQ overwrote aliased controls before reading them");
|
||||||
fpstate._xmm[8].element[0] = 0x1111;
|
fpstate._xmm[8].element[0] = 0x1111;
|
||||||
fpstate._xmm[8].element[2] = 0xdeadbeef;
|
fpstate._xmm[8].element[2] = 0xdeadbeef;
|
||||||
fpstate._xmm[9].element[0] = 0xab;
|
fpstate._xmm[9].element[0] = 0xab;
|
||||||
|
|||||||
Reference in New Issue
Block a user