Updated MMI instructions.

This commit is contained in:
Marco Satti 2018-02-03 22:50:29 +08:00
parent b2a6b71049
commit 4e310e2a77
6 changed files with 438 additions and 268 deletions

View file

@ -157,37 +157,53 @@ void CEeCoreInterpreter::PDIVBW(const EeCoreInstruction inst) const
auto& lo = r.ee.core.r5900.lo;
auto& hi = r.ee.core.r5900.hi;
auto val_source2 = static_cast<shword>(reg_source2->read_uhword(0)); // Constant.
shword divisor = static_cast<shword>(reg_source2->read_uhword(0));
for (auto i = 0; i < NUMBER_WORDS_IN_QWORD; i++)
{
auto val_source1 = static_cast<sword>(reg_source1->read_uword(i));
auto div = [divisor](const uword a) -> std::tuple<uword, uword>
{
sword sa = static_cast<sword>(a);
// Check for VALUE_S32_MIN / -1 (special condition).
if (val_source1 == VALUE_SWORD_MIN &&
val_source2 == -1)
{
lo.write_uword(i, static_cast<sword>(VALUE_SWORD_MIN));
hi.write_uword(i, static_cast<sword>(0));
}
// Check for divide by 0, in which case result is undefined (do nothing).
else if (val_source2 == 0)
{
// TODO: check if old PCSX2 code is required (sets HI to the dividend and LO to 1 or -1 depending on if divisor is positive or negative).
}
// Else perform normal operation.
else
{
sword resultQ = val_source1 / val_source2;
sword resultR = val_source1 % val_source2;
// Check for VALUE_S32_MIN / -1 (special condition).
if (sa == VALUE_SWORD_MIN && divisor == -1)
{
return {
static_cast<uword>(VALUE_SWORD_MIN),
static_cast<uword>(0)
};
}
// Check for divide by 0, in which case result is undefined (do nothing).
else if (divisor == 0)
{
// TODO: check if old PCSX2 code is required (sets HI to the dividend and LO to 1 or -1 depending on if divisor is positive or negative).
return {
static_cast<uword>(0),
static_cast<uword>(0)
};
}
// Else perform normal operation.
else
{
return {
static_cast<uword>(sa / divisor),
static_cast<uword>(sa % divisor)
};
}
};
// Quotient.
lo.write_uword(i, resultQ);
auto[q0, r0] = div(reg_source1->read_uword(0));
auto[q1, r1] = div(reg_source1->read_uword(1));
auto[q2, r2] = div(reg_source1->read_uword(2));
auto[q3, r3] = div(reg_source1->read_uword(3));
// Remainder.
hi.write_uword(i, resultR);
}
}
lo.write_uword(0, q0);
lo.write_uword(1, q1);
lo.write_uword(2, q2);
lo.write_uword(3, q3);
hi.write_uword(0, r0);
hi.write_uword(1, r1);
hi.write_uword(2, r2);
hi.write_uword(3, r3);
}
void CEeCoreInterpreter::PDIVUW(const EeCoreInstruction inst) const
@ -201,29 +217,35 @@ void CEeCoreInterpreter::PDIVUW(const EeCoreInstruction inst) const
auto& lo = r.ee.core.r5900.lo;
auto& hi = r.ee.core.r5900.hi;
for (auto i = 0; i < NUMBER_WORDS_IN_QWORD; i += 2)
{
auto val_source1 = static_cast<uword>(reg_source1->read_uword(i));
auto val_source2 = static_cast<uword>(reg_source2->read_uword(i));
auto div = [](const uword a, const uword b) -> std::tuple<udword, udword>
{
// Check for divide by 0, in which case result is undefined (do nothing).
if (b == 0)
{
// TODO: check if old PCSX2 code is required (sets HI to the dividend and LO to 1 or -1 depending on if divisor is positive or negative).
return {
static_cast<udword>(0),
static_cast<udword>(0)
};
}
// Else perform normal operation.
else
{
return {
static_cast<udword>(static_cast<sdword>(static_cast<sword>(a / b))),
static_cast<udword>(static_cast<sdword>(static_cast<sword>(a % b)))
};
}
};
// Check for divide by 0, in which case result is undefined (do nothing).
if (val_source2 == 0)
{
// TODO: check if old PCSX2 code is required (sets HI to the dividend and LO to -1).
}
// Else perform normal operation.
else
{
udword resultQ = val_source1 / val_source2;
udword resultR = val_source1 % val_source2;
auto[q0, r0] = div(reg_source1->read_uword(0), reg_source2->read_uword(0));
auto[q1, r1] = div(reg_source1->read_uword(2), reg_source2->read_uword(2));
// Quotient.
lo.write_udword(i / 2, resultQ);
lo.write_udword(0, q0);
lo.write_udword(1, q1);
// Remainder.
hi.write_udword(i / 2, resultR);
}
}
hi.write_udword(0, r0);
hi.write_udword(1, r1);
}
void CEeCoreInterpreter::PDIVW(const EeCoreInstruction inst) const
@ -237,36 +259,45 @@ void CEeCoreInterpreter::PDIVW(const EeCoreInstruction inst) const
auto& lo = r.ee.core.r5900.lo;
auto& hi = r.ee.core.r5900.hi;
for (auto i = 0; i < NUMBER_WORDS_IN_QWORD; i += 2)
{
auto val_source1 = static_cast<uword>(reg_source1->read_uword(i));
auto val_source2 = static_cast<uword>(reg_source2->read_uword(i));
auto div = [](const uword a, const uword b) -> std::tuple<udword, udword>
{
sword sa = static_cast<sword>(a);
sword sb = static_cast<sword>(b);
// Check for VALUE_S32_MIN / -1 (special condition).
if (val_source1 == VALUE_SWORD_MIN &&
val_source2 == -1)
{
lo.write_udword(i / 2, static_cast<sdword>(VALUE_SWORD_MIN));
hi.write_udword(i / 2, static_cast<sdword>(0));
}
// Check for divide by 0, in which case result is undefined (do nothing).
else if (val_source2 == 0)
{
// TODO: check if old PCSX2 code is required (sets HI to the dividend and LO to 1 or -1 depending on if divisor is positive or negative).
}
// Else perform normal operation.
else
{
udword resultQ = val_source1 / val_source2;
udword resultR = val_source1 % val_source2;
if (a == VALUE_SWORD_MIN && b == -1)
{
return {
static_cast<udword>(static_cast<sdword>(VALUE_SWORD_MIN)),
static_cast<udword>(static_cast<sdword>(0))
};
}
// Check for divide by 0, in which case result is undefined (do nothing).
if (b == 0)
{
// TODO: check if old PCSX2 code is required (sets HI to the dividend and LO to 1 or -1 depending on if divisor is positive or negative).
return {
static_cast<udword>(0),
static_cast<udword>(0)
};
}
// Else perform normal operation.
else
{
return {
static_cast<udword>(static_cast<sdword>(sa / sb)),
static_cast<udword>(static_cast<sdword>(sa % sb))
};
}
};
// Quotient.
lo.write_udword(i / 2, resultQ);
auto[q0, r0] = div(reg_source1->read_uword(0), reg_source2->read_uword(0));
auto[q1, r1] = div(reg_source1->read_uword(2), reg_source2->read_uword(2));
// Remainder.
hi.write_udword(i / 2, resultR);
}
}
lo.write_udword(0, q0);
lo.write_udword(1, q1);
hi.write_udword(0, r0);
hi.write_udword(1, r1);
}
void CEeCoreInterpreter::PMULTH(const EeCoreInstruction inst) const
@ -281,20 +312,38 @@ void CEeCoreInterpreter::PMULTH(const EeCoreInstruction inst) const
auto& lo = r.ee.core.r5900.lo;
auto& hi = r.ee.core.r5900.hi;
for (auto i = 0; i < NUMBER_HWORDS_IN_QWORD; i++)
{
auto val_source1 = static_cast<shword>(reg_source1->read_uhword(i));
auto val_source2 = static_cast<shword>(reg_source2->read_uhword(i));
sword result = val_source1 * val_source2;
uword value[NUMBER_HWORDS_IN_QWORD];
if (i % 2 == 0)
reg_dest->write_uword(i / 2, result); // Write to Rd for even indexes. A0xB0, A2xB2, A4xB4, A6xB6.
auto mult = [](const uhword a, const uhword b) -> uword
{
sword sa = static_cast<sword>(static_cast<shword>(a));
sword sb = static_cast<sword>(static_cast<shword>(b));
return static_cast<uword>(sa * sb);
};
if ((i / 2) % 2 == 0)
lo.write_uword(((i / 2 > 0) ? i - 2 : i), result); // A0xB0, A1xB1, A4xB4, A5xB5. Array ternary operator is to select the correct index from 0 -> 3.
else
hi.write_uword(((i / 2 > 1) ? i - 4 : i - 2), result); // A2xB2, A3xB3, A6xB6, A7xB7. Array ternary operator is to select the correct index from 0 -> 3.
}
value[0] = mult(reg_source1->read_uhword(0), reg_source2->read_uhword(0));
value[1] = mult(reg_source1->read_uhword(1), reg_source2->read_uhword(1));
value[2] = mult(reg_source1->read_uhword(2), reg_source2->read_uhword(2));
value[3] = mult(reg_source1->read_uhword(3), reg_source2->read_uhword(3));
value[4] = mult(reg_source1->read_uhword(4), reg_source2->read_uhword(4));
value[5] = mult(reg_source1->read_uhword(5), reg_source2->read_uhword(5));
value[6] = mult(reg_source1->read_uhword(6), reg_source2->read_uhword(6));
value[7] = mult(reg_source1->read_uhword(7), reg_source2->read_uhword(7));
reg_dest->write_uword(0, value[0]);
reg_dest->write_uword(1, value[2]);
reg_dest->write_uword(2, value[4]);
reg_dest->write_uword(3, value[6]);
lo.write_uword(0, value[0]);
lo.write_uword(1, value[1]);
lo.write_uword(2, value[4]);
lo.write_uword(3, value[5]);
hi.write_uword(0, value[2]);
hi.write_uword(1, value[3]);
hi.write_uword(2, value[6]);
hi.write_uword(3, value[7]);
}
void CEeCoreInterpreter::PMULTUW(const EeCoreInstruction inst) const
@ -309,16 +358,29 @@ void CEeCoreInterpreter::PMULTUW(const EeCoreInstruction inst) const
auto& lo = r.ee.core.r5900.lo;
auto& hi = r.ee.core.r5900.hi;
for (auto i = 0; i < NUMBER_WORDS_IN_QWORD; i += 2)
{
auto val_source1 = static_cast<uword>(reg_source1->read_uword(i));
auto val_source2 = static_cast<uword>(reg_source2->read_uword(i));
udword result = val_source1 * val_source2;
auto mult = [](const uword a, const uword b) -> std::tuple<udword, udword, udword>
{
udword da = static_cast<udword>(a);
udword db = static_cast<udword>(b);
udword result = da * db;
return {
result,
static_cast<udword>(static_cast<sdword>(static_cast<sword>(result & 0xFFFFFFFF))),
static_cast<udword>(static_cast<sdword>(static_cast<sword>(result >> 32)))
};
};
lo.write_udword(i / 2, static_cast<udword>(static_cast<uword>(result & 0xFFFFFFFF)));
hi.write_udword(i / 2, static_cast<udword>(static_cast<uword>(result >> 32)));
reg_dest->write_udword(i / 2, result);
}
auto[value0, lo0, hi0] = mult(reg_source1->read_uword(0), reg_source1->read_uword(0));
auto[value1, lo1, hi1] = mult(reg_source1->read_uword(2), reg_source1->read_uword(2));
reg_dest->write_udword(0, value0);
reg_dest->write_udword(1, value0);
lo.write_udword(0, lo0);
lo.write_udword(1, lo1);
hi.write_udword(0, hi0);
hi.write_udword(1, hi1);
}
void CEeCoreInterpreter::PMULTW(const EeCoreInstruction inst) const
@ -333,14 +395,27 @@ void CEeCoreInterpreter::PMULTW(const EeCoreInstruction inst) const
auto& lo = r.ee.core.r5900.lo;
auto& hi = r.ee.core.r5900.hi;
for (auto i = 0; i < NUMBER_WORDS_IN_QWORD; i += 2)
{
auto val_source1 = static_cast<sword>(reg_source1->read_uword(i));
auto val_source2 = static_cast<sword>(reg_source2->read_uword(i));
sdword result = val_source1 * val_source2;
auto mult = [](const uword a, const uword b) -> std::tuple<udword, udword, udword>
{
sdword sda = static_cast<sdword>(static_cast<sword>(a));
sdword sdb = static_cast<sdword>(static_cast<sword>(b));
sdword result = sda * sdb;
return {
static_cast<udword>(result),
static_cast<udword>(static_cast<sdword>(static_cast<sword>(result & 0xFFFFFFFF))),
static_cast<udword>(static_cast<sdword>(static_cast<sword>(result >> 32)))
};
};
lo.write_udword(i / 2, static_cast<sdword>(static_cast<sword>(result & 0xFFFFFFFF)));
hi.write_udword(i / 2, static_cast<sdword>(static_cast<sword>(result >> 32)));
reg_dest->write_udword(i / 2, result);
}
auto[value0, lo0, hi0] = mult(reg_source1->read_uword(0), reg_source1->read_uword(0));
auto[value1, lo1, hi1] = mult(reg_source1->read_uword(2), reg_source1->read_uword(2));
reg_dest->write_udword(0, value0);
reg_dest->write_udword(1, value0);
lo.write_udword(0, lo0);
lo.write_udword(1, lo1);
hi.write_udword(0, hi0);
hi.write_udword(1, hi1);
}

View file

@ -17,13 +17,20 @@ void CEeCoreInterpreter::PMAXH(const EeCoreInstruction inst) const
auto& reg_source2 = r.ee.core.r5900.gpr[inst.rt()];
auto& reg_dest = r.ee.core.r5900.gpr[inst.rd()];
for (auto i = 0; i < NUMBER_HWORDS_IN_QWORD; i++)
{
auto val_source1 = static_cast<shword>(reg_source1->read_uhword(i));
auto val_source2 = static_cast<shword>(reg_source2->read_uhword(i));
shword result = std::max(val_source2, val_source1); // Format parameters this way as std::max returns parameter 0 if they are equal, and value in Rt is returned according to docs if they are equal.
reg_dest->write_uhword(i, result);
}
uhword value[NUMBER_HWORDS_IN_QWORD];
auto max = [](const uhword a, const uhword b) -> uhword
{
shword sa = static_cast<shword>(a);
shword sb = static_cast<shword>(b);
return static_cast<uhword>(std::max(a, b));
};
for (auto i = 0; i < NUMBER_HWORDS_IN_QWORD; i++)
value[i] = max(reg_source1->read_uhword(i), reg_source2->read_uhword(i));
for (auto i = 0; i < NUMBER_HWORDS_IN_QWORD; i++)
reg_dest->write_uhword(i, value[i]);
}
void CEeCoreInterpreter::PMAXW(const EeCoreInstruction inst) const
@ -36,13 +43,20 @@ void CEeCoreInterpreter::PMAXW(const EeCoreInstruction inst) const
auto& reg_source2 = r.ee.core.r5900.gpr[inst.rt()];
auto& reg_dest = r.ee.core.r5900.gpr[inst.rd()];
for (auto i = 0; i < NUMBER_WORDS_IN_QWORD; i++)
{
auto val_source1 = static_cast<sword>(reg_source1->read_uword(i));
auto val_source2 = static_cast<sword>(reg_source2->read_uword(i));
sword result = std::max(val_source2, val_source1); // Format parameters this way as std::max returns parameter 0 if they are equal, and value in Rt is returned according to docs if they are equal.
reg_dest->write_uword(i, result);
}
uword value[NUMBER_WORDS_IN_QWORD];
auto max = [](const uword a, const uword b) -> uword
{
sword sa = static_cast<sword>(a);
sword sb = static_cast<sword>(b);
return static_cast<uword>(std::max(a, b));
};
for (auto i = 0; i < NUMBER_WORDS_IN_QWORD; i++)
value[i] = max(reg_source1->read_uword(i), reg_source2->read_uword(i));
for (auto i = 0; i < NUMBER_WORDS_IN_QWORD; i++)
reg_dest->write_uword(i, value[i]);
}
void CEeCoreInterpreter::PMINH(const EeCoreInstruction inst) const
@ -55,13 +69,20 @@ void CEeCoreInterpreter::PMINH(const EeCoreInstruction inst) const
auto& reg_source2 = r.ee.core.r5900.gpr[inst.rt()];
auto& reg_dest = r.ee.core.r5900.gpr[inst.rd()];
for (auto i = 0; i < NUMBER_HWORDS_IN_QWORD; i++)
{
auto val_source1 = static_cast<shword>(reg_source1->read_uhword(i));
auto val_source2 = static_cast<shword>(reg_source2->read_uhword(i));
shword result = std::min(val_source1, val_source2); // Format parameters this way as std::min returns parameter 0 if they are equal, and value in Rs is returned according to docs if they are equal.
reg_dest->write_uhword(i, result);
}
uhword value[NUMBER_HWORDS_IN_QWORD];
auto max = [](const uhword a, const uhword b) -> uhword
{
shword sa = static_cast<shword>(a);
shword sb = static_cast<shword>(b);
return static_cast<uhword>(std::min(a, b));
};
for (auto i = 0; i < NUMBER_HWORDS_IN_QWORD; i++)
value[i] = max(reg_source1->read_uhword(i), reg_source2->read_uhword(i));
for (auto i = 0; i < NUMBER_HWORDS_IN_QWORD; i++)
reg_dest->write_uhword(i, value[i]);
}
void CEeCoreInterpreter::PMINW(const EeCoreInstruction inst) const
@ -74,13 +95,20 @@ void CEeCoreInterpreter::PMINW(const EeCoreInstruction inst) const
auto& reg_source2 = r.ee.core.r5900.gpr[inst.rt()];
auto& reg_dest = r.ee.core.r5900.gpr[inst.rd()];
for (auto i = 0; i < NUMBER_WORDS_IN_QWORD; i++)
{
auto val_source1 = static_cast<sword>(reg_source1->read_uword(i));
auto val_source2 = static_cast<sword>(reg_source2->read_uword(i));
sword result = std::min(val_source1, val_source2); // Format parameters this way as std::min returns parameter 0 if they are equal, and value in Rs is returned according to docs if they are equal.
reg_dest->write_uword(i, result);
}
uword value[NUMBER_WORDS_IN_QWORD];
auto max = [](const uword a, const uword b) -> uword
{
sword sa = static_cast<sword>(a);
sword sb = static_cast<sword>(b);
return static_cast<uword>(std::min(a, b));
};
for (auto i = 0; i < NUMBER_WORDS_IN_QWORD; i++)
value[i] = max(reg_source1->read_uword(i), reg_source2->read_uword(i));
for (auto i = 0; i < NUMBER_WORDS_IN_QWORD; i++)
reg_dest->write_uword(i, value[i]);
}
void CEeCoreInterpreter::MAX_S(const EeCoreInstruction inst) const

View file

@ -169,19 +169,22 @@ void CEeCoreInterpreter::PMFHL_LH(const EeCoreInstruction inst) const
// Rd = (HI, LO). No exceptions.
auto& reg_dest = r.ee.core.r5900.gpr[inst.rd()];
auto& reg_source1 = r.ee.core.r5900.hi;
auto& reg_source2 = r.ee.core.r5900.lo;
auto& hi = r.ee.core.r5900.hi;
auto& lo = r.ee.core.r5900.lo;
// Use mappings to implement this instruction, -1 means not used, and >0 number means the index within Rd.
sword HIIndex[] = { 2, -1, 3, -1, 6, -1, 7, -1 };
sword LOIndex[] = { 0, -1, 1, -1, 4, -1, 5, -1 };
for (auto i = 0; i < NUMBER_HWORDS_IN_QWORD; i++)
{
if (HIIndex[i] != -1)
reg_dest->write_uhword(HIIndex[i], reg_source1.read_uhword(i));
if (LOIndex[i] != -1)
reg_dest->write_uhword(LOIndex[i], reg_source2.read_uhword(i));
}
uhword value[NUMBER_HWORDS_IN_QWORD];
value[0] = lo.read_uhword(0);
value[1] = lo.read_uhword(2);
value[2] = hi.read_uhword(0);
value[3] = hi.read_uhword(2);
value[4] = lo.read_uhword(4);
value[5] = lo.read_uhword(6);
value[6] = hi.read_uhword(4);
value[7] = hi.read_uhword(6);
for (int i = 0; i < NUMBER_HWORDS_IN_QWORD; i++)
reg_dest->write_uhword(i, value[i]);
}
void CEeCoreInterpreter::PMFHL_LW(const EeCoreInstruction inst) const
@ -190,19 +193,18 @@ void CEeCoreInterpreter::PMFHL_LW(const EeCoreInstruction inst) const
// Rd = (HI, LO). No exceptions.
auto& reg_dest = r.ee.core.r5900.gpr[inst.rd()];
auto& reg_source1 = r.ee.core.r5900.hi;
auto& reg_source2 = r.ee.core.r5900.lo;
auto& hi = r.ee.core.r5900.hi;
auto& lo = r.ee.core.r5900.lo;
// Use mappings to implement this instruction, -1 means not used, and >0 number means the index within Rd.
sword HIIndex[] = { 1, -1, 3, -1 };
sword LOIndex[] = { 0, -1, 2, -1 };
for (auto i = 0; i < NUMBER_WORDS_IN_QWORD; i++)
{
if (HIIndex[i] != -1)
reg_dest->write_uword(HIIndex[i], reg_source1.read_uword(i));
if (LOIndex[i] != -1)
reg_dest->write_uword(LOIndex[i], reg_source2.read_uword(i));
}
uword value[NUMBER_WORDS_IN_QWORD];
value[0] = lo.read_uword(0);
value[1] = hi.read_uword(0);
value[2] = lo.read_uword(2);
value[3] = hi.read_uword(2);
for (int i = 0; i < NUMBER_WORDS_IN_QWORD; i++)
reg_dest->write_uword(i, value[i]);
}
void CEeCoreInterpreter::PMFHL_SH(const EeCoreInstruction inst) const
@ -211,22 +213,29 @@ void CEeCoreInterpreter::PMFHL_SH(const EeCoreInstruction inst) const
// Rd = (HI, LO). No exceptions.
auto& reg_dest = r.ee.core.r5900.gpr[inst.rd()];
auto& reg_source1 = r.ee.core.r5900.hi;
auto& reg_source2 = r.ee.core.r5900.lo;
auto& hi = r.ee.core.r5900.hi;
auto& lo = r.ee.core.r5900.lo;
// Use mappings to implement this instruction, -1 means not used, and >0 number means the index within Rd.
sword HIIndex[] = { 2, 3, 6, 7 };
sword LOIndex[] = { 0, 1, 4, 5 };
for (auto i = 0; i < NUMBER_WORDS_IN_QWORD; i++)
{
auto val_source1 = static_cast<sword>(reg_source1.read_uword(i));
auto val_source2 = static_cast<sword>(reg_source2.read_uword(i));
uhword value[NUMBER_HWORDS_IN_QWORD];
if (HIIndex[i] != -1)
reg_dest->write_uhword(HIIndex[i], saturating_word_to_hword(val_source1));
if (LOIndex[i] != -1)
reg_dest->write_uhword(LOIndex[i], saturating_word_to_hword(val_source2));
}
auto saturate = [](const uword value) -> uhword
{
sword svalue = static_cast<sword>(value);
shword shvalue = saturate_word_to_hword(svalue);
return static_cast<uhword>(shvalue);
};
value[0] = saturate(lo.read_uword(0));
value[1] = saturate(lo.read_uword(1));
value[2] = saturate(hi.read_uword(0));
value[3] = saturate(hi.read_uword(1));
value[4] = saturate(lo.read_uword(2));
value[5] = saturate(lo.read_uword(3));
value[6] = saturate(hi.read_uword(2));
value[7] = saturate(hi.read_uword(3));
for (int i = 0; i < NUMBER_HWORDS_IN_QWORD; i++)
reg_dest->write_uhword(i, value[i]);
}
void CEeCoreInterpreter::PMFHL_SLW(const EeCoreInstruction inst) const
@ -235,20 +244,22 @@ void CEeCoreInterpreter::PMFHL_SLW(const EeCoreInstruction inst) const
// Rd = (HI, LO). No exceptions.
auto& reg_dest = r.ee.core.r5900.gpr[inst.rd()];
auto& reg_source1 = r.ee.core.r5900.hi;
auto& reg_source2 = r.ee.core.r5900.lo;
auto& hi = r.ee.core.r5900.hi;
auto& lo = r.ee.core.r5900.lo;
// Indexes 0 and 2 get copied.
sdword tempValue;
sword result;
auto clamp = [] (const uword lo, const uword hi) -> udword
{
udword dhi = static_cast<udword>(hi) << 32;
udword dlo = static_cast<udword>(lo);
sdword dvalue = static_cast<sdword>(saturate_dword_to_word(static_cast<sdword>(hi | lo)));
return static_cast<udword>(dvalue);
};
tempValue = static_cast<sdword>((static_cast<udword>(reg_source1.read_uword(0)) << 32) | static_cast<udword>(reg_source2.read_uword(0)));
result = saturating_dword_to_word(tempValue);
reg_dest->write_udword(0, result);
udword value0 = clamp(lo.read_uword(0), hi.read_uword(0));
udword value1 = clamp(lo.read_uword(2), hi.read_uword(2));
tempValue = static_cast<sdword>((static_cast<udword>(reg_source1.read_uword(2)) << 32) | static_cast<udword>(reg_source2.read_uword(2)));
result = saturating_dword_to_word(tempValue);
reg_dest->write_udword(1, result);
reg_dest->write_udword(0, value0);
reg_dest->write_udword(1, value1);
}
void CEeCoreInterpreter::PMFHL_UW(const EeCoreInstruction inst) const
@ -257,19 +268,18 @@ void CEeCoreInterpreter::PMFHL_UW(const EeCoreInstruction inst) const
// Rd = (HI, LO). No exceptions.
auto& reg_dest = r.ee.core.r5900.gpr[inst.rd()];
auto& reg_source1 = r.ee.core.r5900.hi;
auto& reg_source2 = r.ee.core.r5900.lo;
auto& hi = r.ee.core.r5900.hi;
auto& lo = r.ee.core.r5900.lo;
// Use mappings to implement this instruction, -1 means not used, and >0 number means the index within Rd.
sword HIIndex[] = { -1, 1, -1, 3 };
sword LOIndex[] = { -1, 0, -1, 2 };
for (auto i = 0; i < NUMBER_WORDS_IN_QWORD; i++)
{
if (HIIndex[i] != -1)
reg_dest->write_uword(HIIndex[i], reg_source1.read_uword(i));
if (LOIndex[i] != -1)
reg_dest->write_uword(LOIndex[i], reg_source2.read_uword(i));
}
uword value0 = lo.read_uword(1);
uword value1 = hi.read_uword(1);
uword value2 = lo.read_uword(3);
uword value3 = hi.read_uword(3);
reg_dest->write_uword(0, value0);
reg_dest->write_uword(1, value1);
reg_dest->write_uword(2, value2);
reg_dest->write_uword(3, value3);
}
void CEeCoreInterpreter::PMFLO(const EeCoreInstruction inst) const
@ -302,16 +312,19 @@ void CEeCoreInterpreter::PMTHL_LW(const EeCoreInstruction inst) const
// (HI, LO) = Rs. No exceptions.
auto& reg_source1 = r.ee.core.r5900.gpr[inst.rs()];
auto& reg_dest1 = r.ee.core.r5900.hi;
auto& reg_dest2 = r.ee.core.r5900.lo;
auto& hi = r.ee.core.r5900.hi;
auto& lo = r.ee.core.r5900.lo;
for (auto i = 0; i < NUMBER_WORDS_IN_QWORD; i++)
{
if (i % 2 == 0)
reg_dest2.write_uword(i, reg_source1->read_uword(i));
else
reg_dest1.write_uword(i - 1, reg_source1->read_uword(i));
}
uword value0 = reg_source1->read_uword(0);
uword value1 = reg_source1->read_uword(1);
uword value2 = reg_source1->read_uword(2);
uword value3 = reg_source1->read_uword(3);
lo.write_uword(0, value0);
lo.write_uword(2, value2);
hi.write_uword(0, value1);
hi.write_uword(2, value3);
}
void CEeCoreInterpreter::PMTLO(const EeCoreInstruction inst) const

View file

@ -222,12 +222,15 @@ void CEeCoreInterpreter::PSLLH(const EeCoreInstruction inst) const
// No Exceptions generated.
auto& reg_source1 = r.ee.core.r5900.gpr[inst.rt()];
auto& reg_dest = r.ee.core.r5900.gpr[inst.rd()];
ubyte shamt = inst.shamt() & 0xF;
int shamt = inst.shamt() & 0xF;
for (auto i = 0; i < NUMBER_HWORDS_IN_QWORD; i++)
{
reg_dest->write_uhword(i, reg_source1->read_uhword(i) << shamt);
}
uhword value[NUMBER_HWORDS_IN_QWORD];
for (int i = 0; i < NUMBER_HWORDS_IN_QWORD; i++)
value[i] = reg_source1->read_uhword(i) << shamt;
for (int i = 0; i < NUMBER_HWORDS_IN_QWORD; i++)
reg_dest->write_uhword(i, value[i]);
}
void CEeCoreInterpreter::PSLLVW(const EeCoreInstruction inst) const
@ -239,13 +242,25 @@ void CEeCoreInterpreter::PSLLVW(const EeCoreInstruction inst) const
auto& reg_source1 = r.ee.core.r5900.gpr[inst.rt()];
auto& reg_source2 = r.ee.core.r5900.gpr[inst.rs()];
auto& reg_dest = r.ee.core.r5900.gpr[inst.rd()];
auto shift = [](const uword value, const int shamt) -> udword
{
sdword result = static_cast<sdword>(static_cast<sword>(value << shamt));
return static_cast<udword>(result);
};
udword value0 = shift(
reg_source1->read_uword(0),
reg_source2->read_uword(0) & 0x1F
);
for (auto i = 0; i < NUMBER_WORDS_IN_QWORD; i += 2)
{
ubyte shamt = reg_source2->read_uword(i) & 0x1F;
sdword result = static_cast<sdword>(reg_source1->read_uword(i) << shamt);
reg_dest->write_udword(i / 2, result);
}
udword value1 = shift(
reg_source1->read_uword(2),
reg_source2->read_uword(2) & 0x1F
);
reg_dest->write_udword(0, value0);
reg_dest->write_udword(1, value1);
}
void CEeCoreInterpreter::PSLLW(const EeCoreInstruction inst) const
@ -256,12 +271,15 @@ void CEeCoreInterpreter::PSLLW(const EeCoreInstruction inst) const
// No Exceptions generated.
auto& reg_source1 = r.ee.core.r5900.gpr[inst.rt()];
auto& reg_dest = r.ee.core.r5900.gpr[inst.rd()];
ubyte shamt = inst.shamt();
int shamt = inst.shamt();
for (auto i = 0; i < NUMBER_WORDS_IN_QWORD; i++)
{
reg_dest->write_uword(i, reg_source1->read_uword(i) << shamt);
}
uword value[NUMBER_WORDS_IN_QWORD];
for (int i = 0; i < NUMBER_WORDS_IN_QWORD; i++)
value[i] = reg_source1->read_uword(i) << shamt;
for (int i = 0; i < NUMBER_WORDS_IN_QWORD; i++)
reg_dest->write_uword(i, value[i]);
}
void CEeCoreInterpreter::PSRAH(const EeCoreInstruction inst) const
@ -272,12 +290,15 @@ void CEeCoreInterpreter::PSRAH(const EeCoreInstruction inst) const
// No Exceptions generated.
auto& reg_source1 = r.ee.core.r5900.gpr[inst.rt()];
auto& reg_dest = r.ee.core.r5900.gpr[inst.rd()];
ubyte shamt = inst.shamt() & 0xF;
int shamt = inst.shamt() & 0xF;
for (auto i = 0; i < NUMBER_HWORDS_IN_QWORD; i++)
{
reg_dest->write_uhword(i, static_cast<shword>(reg_source1->read_uhword(i)) >> shamt);
}
uhword value[NUMBER_HWORDS_IN_QWORD];
for (int i = 0; i < NUMBER_HWORDS_IN_QWORD; i++)
value[i] = static_cast<uhword>(static_cast<shword>(reg_source1->read_uhword(i)) >> shamt);
for (int i = 0; i < NUMBER_HWORDS_IN_QWORD; i++)
reg_dest->write_uhword(i, value[i]);
}
void CEeCoreInterpreter::PSRAVW(const EeCoreInstruction inst) const
@ -290,12 +311,24 @@ void CEeCoreInterpreter::PSRAVW(const EeCoreInstruction inst) const
auto& reg_source2 = r.ee.core.r5900.gpr[inst.rs()];
auto& reg_dest = r.ee.core.r5900.gpr[inst.rd()];
for (auto i = 0; i < NUMBER_WORDS_IN_QWORD; i += 2)
{
ubyte shamt = reg_source2->read_uword(i) & 0x1F;
sdword result = static_cast<sdword>(static_cast<sword>(reg_source1->read_uword(i)) >> shamt);
reg_dest->write_udword(i / 2, result);
}
auto shift = [](const uword value, const int shamt) -> udword
{
sdword result = static_cast<sdword>(static_cast<sword>(value) >> shamt);
return static_cast<udword>(result);
};
udword value0 = shift(
reg_source1->read_uword(0),
reg_source2->read_uword(0) & 0x1F
);
udword value1 = shift(
reg_source1->read_uword(2),
reg_source2->read_uword(2) & 0x1F
);
reg_dest->write_udword(0, value0);
reg_dest->write_udword(1, value1);
}
void CEeCoreInterpreter::PSRAW(const EeCoreInstruction inst) const
@ -306,12 +339,15 @@ void CEeCoreInterpreter::PSRAW(const EeCoreInstruction inst) const
// No Exceptions generated.
auto& reg_source1 = r.ee.core.r5900.gpr[inst.rt()];
auto& reg_dest = r.ee.core.r5900.gpr[inst.rd()];
ubyte shamt = inst.shamt();
int shamt = inst.shamt();
for (auto i = 0; i < NUMBER_WORDS_IN_QWORD; i++)
{
reg_dest->write_uword(i, static_cast<sword>(reg_source1->read_uword(i)) >> shamt);
}
uword value[NUMBER_WORDS_IN_QWORD];
for (int i = 0; i < NUMBER_WORDS_IN_QWORD; i++)
value[i] = static_cast<uword>(static_cast<sword>(reg_source1->read_uword(i)) >> shamt);
for (int i = 0; i < NUMBER_WORDS_IN_QWORD; i++)
reg_dest->write_uword(i, value[i]);
}
void CEeCoreInterpreter::PSRLH(const EeCoreInstruction inst) const
@ -322,12 +358,15 @@ void CEeCoreInterpreter::PSRLH(const EeCoreInstruction inst) const
// No Exceptions generated.
auto& reg_source1 = r.ee.core.r5900.gpr[inst.rt()];
auto& reg_dest = r.ee.core.r5900.gpr[inst.rd()];
ubyte shamt = inst.shamt() & 0xF;
int shamt = inst.shamt() & 0xF;
for (auto i = 0; i < NUMBER_HWORDS_IN_QWORD; i++)
{
reg_dest->write_uhword(i, reg_source1->read_uhword(i) >> shamt);
}
uhword value[NUMBER_HWORDS_IN_QWORD];
for (int i = 0; i < NUMBER_HWORDS_IN_QWORD; i++)
value[i] = reg_source1->read_uhword(i) >> shamt;
for (int i = 0; i < NUMBER_HWORDS_IN_QWORD; i++)
reg_dest->write_uhword(i, value[i]);
}
void CEeCoreInterpreter::PSRLVW(const EeCoreInstruction inst) const
@ -340,12 +379,24 @@ void CEeCoreInterpreter::PSRLVW(const EeCoreInstruction inst) const
auto& reg_source2 = r.ee.core.r5900.gpr[inst.rs()];
auto& reg_dest = r.ee.core.r5900.gpr[inst.rd()];
for (auto i = 0; i < NUMBER_WORDS_IN_QWORD; i += 2)
{
ubyte shamt = reg_source2->read_uword(i) & 0x1F;
sdword result = static_cast<sdword>(reg_source1->read_uword(i) >> shamt);
reg_dest->write_udword(i / 2, result);
}
auto shift = [](const uword value, const int shamt) -> udword
{
sdword result = static_cast<sdword>(static_cast<sword>(value >> shamt));
return static_cast<udword>(result);
};
udword value0 = shift(
reg_source1->read_uword(0),
reg_source2->read_uword(0) & 0x1F
);
udword value1 = shift(
reg_source1->read_uword(2),
reg_source2->read_uword(2) & 0x1F
);
reg_dest->write_udword(0, value0);
reg_dest->write_udword(1, value1);
}
void CEeCoreInterpreter::PSRLW(const EeCoreInstruction inst) const
@ -356,12 +407,15 @@ void CEeCoreInterpreter::PSRLW(const EeCoreInstruction inst) const
// No Exceptions generated.
auto& reg_source1 = r.ee.core.r5900.gpr[inst.rt()];
auto& reg_dest = r.ee.core.r5900.gpr[inst.rd()];
ubyte shamt = inst.shamt();
int shamt = inst.shamt();
for (auto i = 0; i < NUMBER_WORDS_IN_QWORD; i++)
{
reg_dest->write_uword(i, reg_source1->read_uword(i) >> shamt);
}
uword value[NUMBER_WORDS_IN_QWORD];
for (int i = 0; i < NUMBER_WORDS_IN_QWORD; i++)
value[i] = reg_source1->read_uword(i) >> shamt;
for (int i = 0; i < NUMBER_WORDS_IN_QWORD; i++)
reg_dest->write_uword(i, value[i]);
}
void CEeCoreInterpreter::QFSRV(const EeCoreInstruction inst) const
@ -370,7 +424,7 @@ void CEeCoreInterpreter::QFSRV(const EeCoreInstruction inst) const
// Rd (lower 128-bits) = (Rs || Rt)(256-bit concatenation) >> SA. Logical shift? Not specified, but assumed to be.
// No Exceptions generated.
// TODO: check this instruction... were they high when they created this???
// TODO: check this instruction... not sure how to make this efficient???
auto& reg_source1 = r.ee.core.r5900.gpr[inst.rt()];
auto& reg_source2 = r.ee.core.r5900.gpr[inst.rs()];
auto& reg_dest = r.ee.core.r5900.gpr[inst.rd()];

View file

@ -4,21 +4,21 @@
#include "Utilities/Utilities.hpp"
uword count_leading_bits(sword value)
int count_leading_bits(const sword value)
{
// If the value is 0, return 32 automatically.
if (value == 0)
return 32;
// If the sign bit is 1, we invert the bits to 0 for count-leading-zero.
if (value < 0)
value = ~value;
// If the sign bit is 1, we invert the bits to 0 for count-leading-zero.
sword conditioned = value < 0 ? ~value : value;
// Perform our count leading zero.
uword num_leading_bits = 0;
for (int i = CHAR_BIT * sizeof value; i > 0; i--)
int num_leading_bits = 0;
for (int i = CHAR_BIT * sizeof(conditioned); i > 0; i--)
{
if ((value & (1 << (i - 1))) == 0)
if ((conditioned & (1 << (i - 1))) == 0)
num_leading_bits++;
else
break;
@ -27,17 +27,17 @@ uword count_leading_bits(sword value)
return num_leading_bits;
}
shword saturating_word_to_hword(sword value)
shword saturate_word_to_hword(const sword value)
{
if (value > VALUE_SHWORD_MAX)
if (value > static_cast<sword>(VALUE_SHWORD_MAX))
return VALUE_SHWORD_MAX;
else if (value < VALUE_SHWORD_MIN)
else if (value < static_cast<sword>(VALUE_SHWORD_MIN))
return VALUE_SHWORD_MIN;
else
return static_cast<shword>(value);
}
sword saturating_dword_to_word(sdword value)
sword saturate_dword_to_word(const sdword value)
{
if (value > VALUE_SWORD_MAX)
return VALUE_SWORD_MAX;

View file

@ -14,15 +14,15 @@ ubyte get_float_exponent(const f32 value);
/// Counts leading bits (1's) from a 32-bit value.
/// Example: in 0b1110001..., the answer is 3.
uword count_leading_bits(sword value); // Adapted from the old PCSX2 code and Stackoverflow (see inside body). Thanks everyone!
int count_leading_bits(const sword value);
/// Saturates/clamps values to the next smallest size, if above the maximum value allowed.
/// Saturates values to the next smallest size, if above the maximum value allowed.
/// Eg: for 0x02345678 to hword, this becomes 0x7FFF;
shword saturating_word_to_hword(sword value);
sword saturating_dword_to_word(sdword value);
shword saturate_word_to_hword(const sword value);
sword saturate_dword_to_word(const sdword value);
/// Provided x and y, returns a bool for the condition that addition it will not overflow, and for subtraction it will not underflow.
/// User must select the appropriate bit size (ie 32, 64).
/// Thanks to http://stackoverflow.com/questions/199333/how-to-detect-integer-overflow-in-c-c
bool test_over_or_underflow_32(sword x, sword y);
bool test_over_or_underflow_64(sdword x, sdword y);
bool test_over_or_underflow_32(const sword x, const sword y);
bool test_over_or_underflow_64(const sdword x, const sdword y);