mirror of
https://github.com/WinampDesktop/winamp.git
synced 2025-04-27 08:45:42 -04:00
CPU/Recompiler: Implement b{gez,ltz}(al)?
This commit is contained in:
parent
167e2a3454
commit
641e68db95
@ -60,8 +60,9 @@ To access the menus with the controller, press the right stick down and use the
|
|||||||
- Passes amidog's CPU and GTE tests, partial passing of CPX tests
|
- Passes amidog's CPU and GTE tests, partial passing of CPX tests
|
||||||
|
|
||||||
## Screenshots
|
## Screenshots
|
||||||

|

|
||||||

|

|
||||||
|

|
||||||
|
|
||||||
## Disclaimers
|
## Disclaimers
|
||||||
|
|
||||||
|
@ -93,6 +93,7 @@ bool CodeGenerator::CompileInstruction(const CodeBlockInstruction& cbi)
|
|||||||
|
|
||||||
case InstructionOp::j:
|
case InstructionOp::j:
|
||||||
case InstructionOp::jal:
|
case InstructionOp::jal:
|
||||||
|
case InstructionOp::b:
|
||||||
case InstructionOp::beq:
|
case InstructionOp::beq:
|
||||||
case InstructionOp::bne:
|
case InstructionOp::bne:
|
||||||
case InstructionOp::bgtz:
|
case InstructionOp::bgtz:
|
||||||
@ -1029,7 +1030,7 @@ bool CodeGenerator::Compile_Branch(const CodeBlockInstruction& cbi)
|
|||||||
OrValues(AndValues(m_register_cache.ReadGuestRegister(Reg::pc, false), Value::FromConstantU32(0xF0000000)),
|
OrValues(AndValues(m_register_cache.ReadGuestRegister(Reg::pc, false), Value::FromConstantU32(0xF0000000)),
|
||||||
Value::FromConstantU32(cbi.instruction.j.target << 2));
|
Value::FromConstantU32(cbi.instruction.j.target << 2));
|
||||||
|
|
||||||
EmitBranch(Condition::Always, (cbi.instruction.op == InstructionOp::jal) ? Reg::ra : Reg::count,
|
EmitBranch(Condition::Always, (cbi.instruction.op == InstructionOp::jal) ? Reg::ra : Reg::count, false,
|
||||||
std::move(branch_target));
|
std::move(branch_target));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1041,15 +1042,13 @@ bool CodeGenerator::Compile_Branch(const CodeBlockInstruction& cbi)
|
|||||||
// npc = rs, link to rt
|
// npc = rs, link to rt
|
||||||
Value branch_target = m_register_cache.ReadGuestRegister(cbi.instruction.r.rs);
|
Value branch_target = m_register_cache.ReadGuestRegister(cbi.instruction.r.rs);
|
||||||
EmitBranch(Condition::Always,
|
EmitBranch(Condition::Always,
|
||||||
(cbi.instruction.r.funct == InstructionFunct::jalr) ? cbi.instruction.r.rd : Reg::count,
|
(cbi.instruction.r.funct == InstructionFunct::jalr) ? cbi.instruction.r.rd : Reg::count, false,
|
||||||
std::move(branch_target));
|
std::move(branch_target));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case InstructionOp::beq:
|
case InstructionOp::beq:
|
||||||
case InstructionOp::bne:
|
case InstructionOp::bne:
|
||||||
case InstructionOp::bgtz:
|
|
||||||
case InstructionOp::blez:
|
|
||||||
{
|
{
|
||||||
// npc = pc + (sext(imm) << 2)
|
// npc = pc + (sext(imm) << 2)
|
||||||
Value branch_target = AddValues(m_register_cache.ReadGuestRegister(Reg::pc, false),
|
Value branch_target = AddValues(m_register_cache.ReadGuestRegister(Reg::pc, false),
|
||||||
@ -1060,27 +1059,42 @@ bool CodeGenerator::Compile_Branch(const CodeBlockInstruction& cbi)
|
|||||||
Value rhs = m_register_cache.ReadGuestRegister(cbi.instruction.i.rt);
|
Value rhs = m_register_cache.ReadGuestRegister(cbi.instruction.i.rt);
|
||||||
EmitCmp(lhs.host_reg, rhs);
|
EmitCmp(lhs.host_reg, rhs);
|
||||||
|
|
||||||
Condition condition;
|
const Condition condition = (cbi.instruction.op == InstructionOp::beq) ? Condition::Equal : Condition::NotEqual;
|
||||||
switch (cbi.instruction.op)
|
EmitBranch(condition, Reg::count, false, std::move(branch_target));
|
||||||
{
|
}
|
||||||
case InstructionOp::beq:
|
break;
|
||||||
condition = Condition::Equal;
|
|
||||||
break;
|
|
||||||
case InstructionOp::bne:
|
|
||||||
condition = Condition::NotEqual;
|
|
||||||
break;
|
|
||||||
case InstructionOp::bgtz:
|
|
||||||
condition = Condition::GreaterThanZero;
|
|
||||||
break;
|
|
||||||
case InstructionOp::blez:
|
|
||||||
condition = Condition::LessOrEqualToZero;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
condition = Condition::Always;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
EmitBranch(condition, Reg::count, std::move(branch_target));
|
case InstructionOp::bgtz:
|
||||||
|
case InstructionOp::blez:
|
||||||
|
{
|
||||||
|
// npc = pc + (sext(imm) << 2)
|
||||||
|
Value branch_target = AddValues(m_register_cache.ReadGuestRegister(Reg::pc, false),
|
||||||
|
Value::FromConstantU32(cbi.instruction.i.imm_sext32() << 2));
|
||||||
|
|
||||||
|
// branch <- rs op 0
|
||||||
|
Value lhs = m_register_cache.ReadGuestRegister(cbi.instruction.i.rs, true, true);
|
||||||
|
EmitCmp(lhs.host_reg, Value::FromConstantU32(0));
|
||||||
|
|
||||||
|
const Condition condition =
|
||||||
|
(cbi.instruction.op == InstructionOp::bgtz) ? Condition::Greater : Condition::LessOrEqual;
|
||||||
|
EmitBranch(condition, Reg::count, false, std::move(branch_target));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case InstructionOp::b:
|
||||||
|
{
|
||||||
|
// npc = pc + (sext(imm) << 2)
|
||||||
|
Value branch_target = AddValues(m_register_cache.ReadGuestRegister(Reg::pc, false),
|
||||||
|
Value::FromConstantU32(cbi.instruction.i.imm_sext32() << 2));
|
||||||
|
|
||||||
|
const u8 rt = static_cast<u8>(cbi.instruction.i.rt.GetValue());
|
||||||
|
const bool bgez = ConvertToBoolUnchecked(rt & u8(1));
|
||||||
|
const Condition condition = bgez ? Condition::PositiveOrZero : Condition::Negative;
|
||||||
|
const bool link = (rt & u8(0x1E)) == u8(0x10);
|
||||||
|
|
||||||
|
Value lhs = m_register_cache.ReadGuestRegister(cbi.instruction.i.rs, true, true);
|
||||||
|
EmitTest(lhs.host_reg, lhs);
|
||||||
|
EmitBranch(condition, link ? Reg::ra : Reg::count, link, std::move(branch_target));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ public:
|
|||||||
void EmitStoreGuestMemory(const Value& address, const Value& value);
|
void EmitStoreGuestMemory(const Value& address, const Value& value);
|
||||||
|
|
||||||
// Branching, generates two paths.
|
// Branching, generates two paths.
|
||||||
void EmitBranch(Condition condition, Reg lr_reg, Value&& branch_target);
|
void EmitBranch(Condition condition, Reg lr_reg, bool always_link, Value&& branch_target);
|
||||||
|
|
||||||
u32 PrepareStackForCall();
|
u32 PrepareStackForCall();
|
||||||
void RestoreStackAfterCall(u32 adjust_size);
|
void RestoreStackAfterCall(u32 adjust_size);
|
||||||
|
@ -1621,35 +1621,58 @@ static void EmitConditionalJump(Condition condition, bool invert, Xbyak::CodeGen
|
|||||||
invert ? emit->jno(label) : emit->jo(label);
|
invert ? emit->jno(label) : emit->jo(label);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Condition::GreaterThanZero:
|
case Condition::Greater:
|
||||||
invert ? emit->jng(label) : emit->jg(label);
|
invert ? emit->jng(label) : emit->jg(label);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Condition::LessOrEqualToZero:
|
case Condition::GreaterEqual:
|
||||||
|
invert ? emit->jnge(label) : emit->jge(label);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Condition::Less:
|
||||||
|
invert ? emit->jnl(label) : emit->jl(label);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Condition::LessOrEqual:
|
||||||
invert ? emit->jnle(label) : emit->jle(label);
|
invert ? emit->jnle(label) : emit->jle(label);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Condition::Negative:
|
||||||
|
invert ? emit->jns(label) : emit->js(label);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Condition::PositiveOrZero:
|
||||||
|
invert ? emit->js(label) : emit->jns(label);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
UnreachableCode();
|
UnreachableCode();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeGenerator::EmitBranch(Condition condition, Reg lr_reg, Value&& branch_target)
|
void CodeGenerator::EmitBranch(Condition condition, Reg lr_reg, bool always_link, Value&& branch_target)
|
||||||
{
|
{
|
||||||
Xbyak::Label skip_branch;
|
|
||||||
|
|
||||||
// we have to always read the old PC.. when we can push/pop the register cache state this won't be needed
|
// we have to always read the old PC.. when we can push/pop the register cache state this won't be needed
|
||||||
Value old_npc;
|
Value old_npc;
|
||||||
if (lr_reg != Reg::count)
|
if (lr_reg != Reg::count)
|
||||||
|
{
|
||||||
old_npc = m_register_cache.ReadGuestRegister(Reg::npc, false, true);
|
old_npc = m_register_cache.ReadGuestRegister(Reg::npc, false, true);
|
||||||
|
if (always_link)
|
||||||
|
{
|
||||||
|
// can't cache because we have two branches
|
||||||
|
m_register_cache.WriteGuestRegister(lr_reg, std::move(old_npc));
|
||||||
|
m_register_cache.FlushGuestRegister(lr_reg, true, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// condition is inverted because we want the case for skipping it
|
// condition is inverted because we want the case for skipping it
|
||||||
|
Xbyak::Label skip_branch;
|
||||||
if (condition != Condition::Always)
|
if (condition != Condition::Always)
|
||||||
EmitConditionalJump(condition, true, m_emit, skip_branch);
|
EmitConditionalJump(condition, true, m_emit, skip_branch);
|
||||||
|
|
||||||
// save the old PC if we want to
|
// save the old PC if we want to
|
||||||
if (lr_reg != Reg::count)
|
if (lr_reg != Reg::count && !always_link)
|
||||||
{
|
{
|
||||||
// can't cache because we have two branches
|
// can't cache because we have two branches
|
||||||
m_register_cache.WriteGuestRegister(lr_reg, std::move(old_npc));
|
m_register_cache.WriteGuestRegister(lr_reg, std::move(old_npc));
|
||||||
|
@ -30,8 +30,12 @@ enum class Condition: u8
|
|||||||
NotEqual,
|
NotEqual,
|
||||||
Equal,
|
Equal,
|
||||||
Overflow,
|
Overflow,
|
||||||
GreaterThanZero,
|
Greater,
|
||||||
LessOrEqualToZero,
|
GreaterEqual,
|
||||||
|
LessOrEqual,
|
||||||
|
Less,
|
||||||
|
Negative,
|
||||||
|
PositiveOrZero,
|
||||||
|
|
||||||
NotZero = NotEqual,
|
NotZero = NotEqual,
|
||||||
Zero = Equal
|
Zero = Equal
|
||||||
|
Loading…
x
Reference in New Issue
Block a user