Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MIPS r5900 (PS2 EE) support #6311

Open
wants to merge 2 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 46 additions & 10 deletions arch/mips/arch_mips.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,14 +179,16 @@ static const char* GetRelocationString(ElfMipsRelocationType rel)
class MipsArchitecture: public Architecture
{
protected:
bool m_userWarnedAboutDelaySlots = false;
MipsVersion m_version;
size_t m_bits;
BNEndianness m_endian;
uint32_t m_decomposeFlags;

virtual bool Disassemble(const uint8_t* data, uint64_t addr, size_t maxLen, Instruction& result)
{
memset(&result, 0, sizeof(result));
if (mips_decompose((uint32_t*)data, maxLen, &result, m_bits == 64 ? MIPS_64 : MIPS_32, addr, m_endian, m_decomposeFlags) != 0)
if (mips_decompose((uint32_t*)data, maxLen, &result, m_version, addr, m_endian, m_decomposeFlags) != 0)
return false;
return true;
}
Expand Down Expand Up @@ -402,8 +404,8 @@ class MipsArchitecture: public Architecture
}

public:
MipsArchitecture(const std::string& name, BNEndianness endian, size_t bits, uint32_t decomposeFlags = 0)
: Architecture(name), m_bits(bits), m_endian(endian), m_decomposeFlags(decomposeFlags)
MipsArchitecture(const std::string& name, MipsVersion version, BNEndianness endian, size_t bits, uint32_t decomposeFlags = 0): Architecture(name),
m_version(version), m_bits(bits), m_endian(endian), m_decomposeFlags(decomposeFlags)
{
Ref<Settings> settings = Settings::Instance();
uint32_t flag_pseudo_ops = settings->Get<bool>("arch.mips.disassembly.pseudoOps") ? DECOMPOSE_FLAGS_PSEUDO_OP : 0;
Expand Down Expand Up @@ -503,7 +505,16 @@ class MipsArchitecture: public Architecture
{
if (len < 8)
{
LogWarn("Can not lift instruction with delay slot @ 0x%08" PRIx64, addr);
if (!m_userWarnedAboutDelaySlots)
{

LogWarn("Can not lift instruction with delay slot @ 0x%08" PRIx64 "\n"
"Any future delay slot errors will be printed as debug logs\n"
"and can be viewed by setting the log capture level to debug.", addr);
m_userWarnedAboutDelaySlots = true;
}
else
LogDebug("Can not lift instruction with delay slot @ 0x%08" PRIx64, addr);
return false;
}

Expand Down Expand Up @@ -3011,7 +3022,14 @@ class MipsElfRelocationHandler: public RelocationHandler
uint32_t inst2 = *(uint32_t*)(cur->relocationDataCache);
Instruction instruction;
memset(&instruction, 0, sizeof(instruction));
if (mips_decompose(&inst2, sizeof(uint32_t), &instruction, arch->GetAddressSize() == 8 ? MIPS_64 : MIPS_32, cur->address, arch->GetEndianness(), DECOMPOSE_FLAGS_PSEUDO_OP))

MipsVersion version;
if (arch->GetName().substr(0, 5) == "r5900")
version = MIPS_R5900;
else
version = arch->GetAddressSize() == 8 ? MIPS_64 : MIPS_32;

if (mips_decompose(&inst2, sizeof(uint32_t), &instruction, version, cur->address, arch->GetEndianness(), DECOMPOSE_FLAGS_PSEUDO_OP))
break;

int32_t immediate = swap(inst2) & 0xffff;
Expand Down Expand Up @@ -3258,13 +3276,17 @@ extern "C"
{
InitMipsSettings();

Architecture* mipsel = new MipsArchitecture("mipsel32", LittleEndian, 32);
Architecture* mipseb = new MipsArchitecture("mips32", BigEndian, 32);
Architecture* mips64el = new MipsArchitecture("mipsel64", LittleEndian, 64);
Architecture* mips64eb = new MipsArchitecture("mips64", BigEndian, 64);
Architecture* cnmips64eb = new MipsArchitecture("cavium-mips64", BigEndian, 64, DECOMPOSE_FLAGS_CAVIUM);
Architecture* mipsel = new MipsArchitecture("mipsel32", MIPS_32, LittleEndian, 32);
Architecture* mipseb = new MipsArchitecture("mips32", MIPS_32, BigEndian, 32);
Architecture* mips64el = new MipsArchitecture("mipsel64", MIPS_64, LittleEndian, 64);
Architecture* mips64eb = new MipsArchitecture("mips64", MIPS_64, BigEndian, 64);
Architecture* cnmips64eb = new MipsArchitecture("cavium-mips64", MIPS_64, BigEndian, 64, DECOMPOSE_FLAGS_CAVIUM);
Architecture* r5900l = new MipsArchitecture("r5900l", MIPS_R5900, LittleEndian, 32);
Architecture* r5900b = new MipsArchitecture("r5900b", MIPS_R5900, BigEndian, 32);

Architecture::Register(mipsel);
Architecture::Register(r5900l);
Architecture::Register(r5900b);
Architecture::Register(mipseb);
Architecture::Register(mips64el);
Architecture::Register(mips64eb);
Expand All @@ -3278,9 +3300,13 @@ extern "C"
MipsN64CallingConvention* n64BEc = new MipsN64CallingConvention(cnmips64eb);

mipsel->RegisterCallingConvention(o32LE);
r5900l->RegisterCallingConvention(o32LE);
mipseb->RegisterCallingConvention(o32BE);
r5900b->RegisterCallingConvention(o32BE);
mipsel->SetDefaultCallingConvention(o32LE);
r5900l->SetDefaultCallingConvention(o32LE);
mipseb->SetDefaultCallingConvention(o32BE);
r5900b->SetDefaultCallingConvention(o32BE);
mips64el->RegisterCallingConvention(n64LE);
mips64el->SetDefaultCallingConvention(n64LE);
mips64eb->RegisterCallingConvention(n64BE);
Expand All @@ -3289,23 +3315,33 @@ extern "C"
cnmips64eb->SetDefaultCallingConvention(n64BEc);

MipsLinuxSyscallCallingConvention* linuxSyscallLE = new MipsLinuxSyscallCallingConvention(mipsel);
MipsLinuxSyscallCallingConvention* linuxSyscallr5900LE = new MipsLinuxSyscallCallingConvention(r5900l);
MipsLinuxSyscallCallingConvention* linuxSyscallBE = new MipsLinuxSyscallCallingConvention(mipseb);
MipsLinuxSyscallCallingConvention* linuxSyscallr5900BE = new MipsLinuxSyscallCallingConvention(r5900b);
mipsel->RegisterCallingConvention(linuxSyscallLE);
r5900l->RegisterCallingConvention(linuxSyscallr5900LE);
mipseb->RegisterCallingConvention(linuxSyscallBE);
r5900b->RegisterCallingConvention(linuxSyscallr5900BE);

mipsel->RegisterCallingConvention(new MipsLinuxRtlResolveCallingConvention(mipsel));
r5900l->RegisterCallingConvention(new MipsLinuxRtlResolveCallingConvention(r5900l));
mipseb->RegisterCallingConvention(new MipsLinuxRtlResolveCallingConvention(mipseb));
r5900b->RegisterCallingConvention(new MipsLinuxRtlResolveCallingConvention(r5900b));
mips64el->RegisterCallingConvention(new MipsLinuxRtlResolveCallingConvention(mips64el));
mips64eb->RegisterCallingConvention(new MipsLinuxRtlResolveCallingConvention(mips64eb));
cnmips64eb->RegisterCallingConvention(new MipsLinuxRtlResolveCallingConvention(cnmips64eb));

/* function recognizers */
mipsel->RegisterFunctionRecognizer(new MipsImportedFunctionRecognizer());
mipseb->RegisterFunctionRecognizer(new MipsImportedFunctionRecognizer());
r5900l->RegisterFunctionRecognizer(new MipsImportedFunctionRecognizer());
r5900b->RegisterFunctionRecognizer(new MipsImportedFunctionRecognizer());

mipsel->RegisterRelocationHandler("ELF", new MipsElfRelocationHandler());
mipseb->RegisterRelocationHandler("ELF", new MipsElfRelocationHandler());
mips64el->RegisterRelocationHandler("ELF", new MipsElfRelocationHandler());
r5900l->RegisterRelocationHandler("ELF", new MipsElfRelocationHandler());
r5900b->RegisterRelocationHandler("ELF", new MipsElfRelocationHandler());
mips64eb->RegisterRelocationHandler("ELF", new MipsElfRelocationHandler());
cnmips64eb->RegisterRelocationHandler("ELF", new MipsElfRelocationHandler());

Expand Down
78 changes: 78 additions & 0 deletions arch/mips/il.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2146,6 +2146,84 @@ bool GetLowLevelILForInstruction(Architecture* arch, uint64_t addr, LowLevelILFu

break;

case MIPS_MTSAB:
{
auto gprValue = il.Register(4, op1.reg);
auto gprLS4 = il.And(4, gprValue, il.Const(4, 0xF));

// Extract least-significant 4 bits of immediate value
auto immLS4 = il.And(4, il.Const(4, op2.immediate), il.Const(4, 0xF));

// Perform XOR operation between GPR[rs][3:0] and immediate[3:0]
auto xorResult = il.Xor(4, gprLS4, immLS4);

// Multiply result by 8 (equivalent to left shift by 3)
auto shiftAmount = il.ShiftLeft(4, xorResult, il.Const(4, 3));

// Write the result to the SA register
il.AddInstruction(il.SetRegister(4, R5900_SA, shiftAmount));

break;
}
case MIPS_MTSAH:
{
auto rsVal = il.And(4, il.Register(4, op1.reg), il.Const(4, 0b111));
auto immVal = il.Const(4, op2.immediate & 0b111);

// Perform XOR
auto xorVal = il.Xor(4, rsVal, immVal);

// Multiply by 16
auto shiftAmount = il.Mult(4, xorVal, il.Const(4, 16));

// Set the SA register
il.AddInstruction(il.SetRegister(4, R5900_SA, shiftAmount));

break;
}
case MIPS_PADDUW:
{
for (int i = 0; i < 4; i++)
{
size_t offset = i * 32;
auto rs_segment = il.And(16,
il.LogicalShiftRight(
16,
il.Register(16, op2.reg),
il.Const(4, offset)
),
il.Const(128, 0xFFFFFFFF)
);
auto rt_segment = il.And(16,
il.LogicalShiftRight(
16,
il.Register(16, op3.reg),
il.Const(4, offset)
),
il.Const(128, 0xFFFFFFFF)
);

auto sum = il.Add(8, rs_segment, rt_segment);

// This is a 4 byte add, but if the sum is greater than 0xFFFFFFFF, the result is 0xFFFFFFFF
// So we do an 8 bit add and and the result

auto saturated_sum = il.And(4, sum, il.Const(4, 0xFFFFFFFF));

auto shifted_sum = il.ShiftLeft(16, saturated_sum, il.Const(4, offset));
if (i == 0)
{
il.AddInstruction(il.SetRegister(16, op1.reg, shifted_sum));
}
else
{
il.AddInstruction(il.SetRegister(16, op1.reg, il.Or(16, il.Register(16, op1.reg), shifted_sum)));
}
}

break;
}

case MIPS_ADDR:
case MIPS_LDXC1:
case MIPS_LLO:
Expand Down
Loading