mirror of
https://github.com/WinampDesktop/winamp.git
synced 2025-04-27 18:25:41 -04:00
CPU: Implement TAR COP0 register
This commit is contained in:
parent
eddd2c1990
commit
74d51c80fc
@ -33,7 +33,7 @@ void Core::Reset()
|
|||||||
|
|
||||||
m_cop0_regs.BPC = 0;
|
m_cop0_regs.BPC = 0;
|
||||||
m_cop0_regs.BDA = 0;
|
m_cop0_regs.BDA = 0;
|
||||||
m_cop0_regs.JUMPDEST = 0;
|
m_cop0_regs.TAR = 0;
|
||||||
m_cop0_regs.BadVaddr = 0;
|
m_cop0_regs.BadVaddr = 0;
|
||||||
m_cop0_regs.BDAM = 0;
|
m_cop0_regs.BDAM = 0;
|
||||||
m_cop0_regs.BPCM = 0;
|
m_cop0_regs.BPCM = 0;
|
||||||
@ -57,7 +57,7 @@ bool Core::DoState(StateWrapper& sw)
|
|||||||
sw.Do(&m_regs.npc);
|
sw.Do(&m_regs.npc);
|
||||||
sw.Do(&m_cop0_regs.BPC);
|
sw.Do(&m_cop0_regs.BPC);
|
||||||
sw.Do(&m_cop0_regs.BDA);
|
sw.Do(&m_cop0_regs.BDA);
|
||||||
sw.Do(&m_cop0_regs.JUMPDEST);
|
sw.Do(&m_cop0_regs.TAR);
|
||||||
sw.Do(&m_cop0_regs.BadVaddr);
|
sw.Do(&m_cop0_regs.BadVaddr);
|
||||||
sw.Do(&m_cop0_regs.BDAM);
|
sw.Do(&m_cop0_regs.BDAM);
|
||||||
sw.Do(&m_cop0_regs.BPCM);
|
sw.Do(&m_cop0_regs.BPCM);
|
||||||
@ -67,13 +67,16 @@ bool Core::DoState(StateWrapper& sw)
|
|||||||
sw.Do(&m_cop0_regs.cause.bits);
|
sw.Do(&m_cop0_regs.cause.bits);
|
||||||
sw.Do(&m_cop0_regs.dcic.bits);
|
sw.Do(&m_cop0_regs.dcic.bits);
|
||||||
sw.Do(&m_next_instruction.bits);
|
sw.Do(&m_next_instruction.bits);
|
||||||
|
sw.Do(&m_current_instruction.bits);
|
||||||
sw.Do(&m_current_instruction_pc);
|
sw.Do(&m_current_instruction_pc);
|
||||||
|
sw.Do(&m_current_instruction_in_branch_delay_slot);
|
||||||
|
sw.Do(&m_current_instruction_was_branch_taken);
|
||||||
|
sw.Do(&m_next_instruction_is_branch_delay_slot);
|
||||||
|
sw.Do(&m_branch_was_taken);
|
||||||
sw.Do(&m_load_delay_reg);
|
sw.Do(&m_load_delay_reg);
|
||||||
sw.Do(&m_load_delay_old_value);
|
sw.Do(&m_load_delay_old_value);
|
||||||
sw.Do(&m_next_load_delay_reg);
|
sw.Do(&m_next_load_delay_reg);
|
||||||
sw.Do(&m_next_load_delay_old_value);
|
sw.Do(&m_next_load_delay_old_value);
|
||||||
sw.Do(&m_in_branch_delay_slot);
|
|
||||||
sw.Do(&m_branched);
|
|
||||||
sw.Do(&m_cache_control);
|
sw.Do(&m_cache_control);
|
||||||
sw.DoBytes(m_dcache.data(), m_dcache.size());
|
sw.DoBytes(m_dcache.data(), m_dcache.size());
|
||||||
|
|
||||||
@ -202,7 +205,7 @@ bool Core::SafeWriteMemoryWord(VirtualMemoryAddress addr, u32 value)
|
|||||||
void Core::Branch(u32 target)
|
void Core::Branch(u32 target)
|
||||||
{
|
{
|
||||||
m_regs.npc = target;
|
m_regs.npc = target;
|
||||||
m_branched = true;
|
m_branch_was_taken = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 Core::GetExceptionVector(Exception excode) const
|
u32 Core::GetExceptionVector(Exception excode) const
|
||||||
@ -226,15 +229,14 @@ u32 Core::GetExceptionVector(Exception excode) const
|
|||||||
|
|
||||||
void Core::RaiseException(Exception excode)
|
void Core::RaiseException(Exception excode)
|
||||||
{
|
{
|
||||||
const bool BD = m_in_branch_delay_slot;
|
RaiseException(excode, m_current_instruction_pc, m_current_instruction_in_branch_delay_slot,
|
||||||
const u32 EPC = BD ? (m_current_instruction_pc - UINT32_C(4)) : m_current_instruction_pc;
|
m_current_instruction_was_branch_taken, m_current_instruction.cop.cop_n);
|
||||||
RaiseException(excode, EPC, BD, m_current_instruction.cop.cop_n);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Core::RaiseException(Exception excode, u32 EPC, bool BD, u8 CE)
|
void Core::RaiseException(Exception excode, u32 EPC, bool BD, bool BT, u8 CE)
|
||||||
{
|
{
|
||||||
Log_WarningPrintf("Exception %u at 0x%08X (epc=0x%08X, BD=%s, CE=%u)", static_cast<u32>(excode),
|
Log_DevPrintf("Exception %u at 0x%08X (epc=0x%08X, BD=%s, CE=%u)", static_cast<u32>(excode), m_current_instruction_pc,
|
||||||
m_current_instruction_pc, EPC, BD ? "true" : "false", ZeroExtend32(CE));
|
EPC, BD ? "true" : "false", ZeroExtend32(CE));
|
||||||
#ifdef Y_BUILD_CONFIG_DEBUG
|
#ifdef Y_BUILD_CONFIG_DEBUG
|
||||||
DisassembleAndPrint(m_current_instruction_pc, 4, 0);
|
DisassembleAndPrint(m_current_instruction_pc, 4, 0);
|
||||||
#endif
|
#endif
|
||||||
@ -242,8 +244,17 @@ void Core::RaiseException(Exception excode, u32 EPC, bool BD, u8 CE)
|
|||||||
m_cop0_regs.EPC = EPC;
|
m_cop0_regs.EPC = EPC;
|
||||||
m_cop0_regs.cause.Excode = excode;
|
m_cop0_regs.cause.Excode = excode;
|
||||||
m_cop0_regs.cause.BD = BD;
|
m_cop0_regs.cause.BD = BD;
|
||||||
|
m_cop0_regs.cause.BT = BT;
|
||||||
m_cop0_regs.cause.CE = CE;
|
m_cop0_regs.cause.CE = CE;
|
||||||
|
|
||||||
|
if (BD)
|
||||||
|
{
|
||||||
|
// TAR is set to the address which was being fetched in this instruction, or the next instruction to execute if the
|
||||||
|
// exception hadn't occurred in the delay slot.
|
||||||
|
m_cop0_regs.EPC -= UINT32_C(4);
|
||||||
|
m_cop0_regs.TAR = m_regs.pc;
|
||||||
|
}
|
||||||
|
|
||||||
// current -> previous, switch to kernel mode and disable interrupts
|
// current -> previous, switch to kernel mode and disable interrupts
|
||||||
m_cop0_regs.sr.mode_bits <<= 2;
|
m_cop0_regs.sr.mode_bits <<= 2;
|
||||||
|
|
||||||
@ -293,8 +304,8 @@ void Core::FlushPipeline()
|
|||||||
FlushLoadDelay();
|
FlushLoadDelay();
|
||||||
|
|
||||||
// not in a branch delay slot
|
// not in a branch delay slot
|
||||||
m_branched = false;
|
m_branch_was_taken = false;
|
||||||
m_in_branch_delay_slot = false;
|
m_next_instruction_is_branch_delay_slot = false;
|
||||||
|
|
||||||
// prefetch the next instruction
|
// prefetch the next instruction
|
||||||
FetchInstruction();
|
FetchInstruction();
|
||||||
@ -343,7 +354,7 @@ u32 Core::ReadCop0Reg(Cop0Reg reg)
|
|||||||
return m_cop0_regs.dcic.bits;
|
return m_cop0_regs.dcic.bits;
|
||||||
|
|
||||||
case Cop0Reg::JUMPDEST:
|
case Cop0Reg::JUMPDEST:
|
||||||
return m_cop0_regs.JUMPDEST;
|
return m_cop0_regs.TAR;
|
||||||
|
|
||||||
case Cop0Reg::BadVaddr:
|
case Cop0Reg::BadVaddr:
|
||||||
return m_cop0_regs.BadVaddr;
|
return m_cop0_regs.BadVaddr;
|
||||||
@ -494,10 +505,10 @@ void Core::Execute()
|
|||||||
// now executing the instruction we previously fetched
|
// now executing the instruction we previously fetched
|
||||||
m_current_instruction = m_next_instruction;
|
m_current_instruction = m_next_instruction;
|
||||||
m_current_instruction_pc = m_regs.pc;
|
m_current_instruction_pc = m_regs.pc;
|
||||||
|
m_current_instruction_in_branch_delay_slot = m_next_instruction_is_branch_delay_slot;
|
||||||
// handle branch delays - we are now in a delay slot if we just branched
|
m_current_instruction_was_branch_taken = m_branch_was_taken;
|
||||||
m_in_branch_delay_slot = m_branched;
|
m_next_instruction_is_branch_delay_slot = false;
|
||||||
m_branched = false;
|
m_branch_was_taken = false;
|
||||||
|
|
||||||
// fetch the next instruction
|
// fetch the next instruction
|
||||||
if (DispatchInterrupts() || !FetchInstruction())
|
if (DispatchInterrupts() || !FetchInstruction())
|
||||||
@ -520,13 +531,13 @@ bool Core::FetchInstruction()
|
|||||||
{
|
{
|
||||||
// The EPC must be set to the fetching address, not the instruction about to execute.
|
// The EPC must be set to the fetching address, not the instruction about to execute.
|
||||||
m_cop0_regs.BadVaddr = m_regs.npc;
|
m_cop0_regs.BadVaddr = m_regs.npc;
|
||||||
RaiseException(Exception::AdEL, m_regs.npc, false, 0);
|
RaiseException(Exception::AdEL, m_regs.npc, false, false, 0);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (!DoMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::Word>(m_regs.npc, m_next_instruction.bits))
|
else if (!DoMemoryAccess<MemoryAccessType::Read, MemoryAccessSize::Word>(m_regs.npc, m_next_instruction.bits))
|
||||||
{
|
{
|
||||||
// Bus errors don't set BadVaddr.
|
// Bus errors don't set BadVaddr.
|
||||||
RaiseException(Exception::IBE, m_regs.npc, false, 0);
|
RaiseException(Exception::IBE, m_regs.npc, false, false, 0);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -780,6 +791,7 @@ void Core::ExecuteInstruction()
|
|||||||
|
|
||||||
case InstructionFunct::jr:
|
case InstructionFunct::jr:
|
||||||
{
|
{
|
||||||
|
m_next_instruction_is_branch_delay_slot = true;
|
||||||
const u32 target = ReadReg(inst.r.rs);
|
const u32 target = ReadReg(inst.r.rs);
|
||||||
Branch(target);
|
Branch(target);
|
||||||
}
|
}
|
||||||
@ -787,6 +799,7 @@ void Core::ExecuteInstruction()
|
|||||||
|
|
||||||
case InstructionFunct::jalr:
|
case InstructionFunct::jalr:
|
||||||
{
|
{
|
||||||
|
m_next_instruction_is_branch_delay_slot = true;
|
||||||
const u32 target = ReadReg(inst.r.rs);
|
const u32 target = ReadReg(inst.r.rs);
|
||||||
WriteReg(inst.r.rd, m_regs.npc);
|
WriteReg(inst.r.rd, m_regs.npc);
|
||||||
Branch(target);
|
Branch(target);
|
||||||
@ -1008,6 +1021,7 @@ void Core::ExecuteInstruction()
|
|||||||
|
|
||||||
case InstructionOp::j:
|
case InstructionOp::j:
|
||||||
{
|
{
|
||||||
|
m_next_instruction_is_branch_delay_slot = true;
|
||||||
Branch((m_regs.pc & UINT32_C(0xF0000000)) | (inst.j.target << 2));
|
Branch((m_regs.pc & UINT32_C(0xF0000000)) | (inst.j.target << 2));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1015,12 +1029,15 @@ void Core::ExecuteInstruction()
|
|||||||
case InstructionOp::jal:
|
case InstructionOp::jal:
|
||||||
{
|
{
|
||||||
m_regs.ra = m_regs.npc;
|
m_regs.ra = m_regs.npc;
|
||||||
|
m_next_instruction_is_branch_delay_slot = true;
|
||||||
Branch((m_regs.pc & UINT32_C(0xF0000000)) | (inst.j.target << 2));
|
Branch((m_regs.pc & UINT32_C(0xF0000000)) | (inst.j.target << 2));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case InstructionOp::beq:
|
case InstructionOp::beq:
|
||||||
{
|
{
|
||||||
|
// We're still flagged as a branch delay slot even if the branch isn't taken.
|
||||||
|
m_next_instruction_is_branch_delay_slot = true;
|
||||||
const bool branch = (ReadReg(inst.i.rs) == ReadReg(inst.i.rt));
|
const bool branch = (ReadReg(inst.i.rs) == ReadReg(inst.i.rt));
|
||||||
if (branch)
|
if (branch)
|
||||||
Branch(m_regs.pc + (inst.i.imm_sext32() << 2));
|
Branch(m_regs.pc + (inst.i.imm_sext32() << 2));
|
||||||
@ -1029,6 +1046,7 @@ void Core::ExecuteInstruction()
|
|||||||
|
|
||||||
case InstructionOp::bne:
|
case InstructionOp::bne:
|
||||||
{
|
{
|
||||||
|
m_next_instruction_is_branch_delay_slot = true;
|
||||||
const bool branch = (ReadReg(inst.i.rs) != ReadReg(inst.i.rt));
|
const bool branch = (ReadReg(inst.i.rs) != ReadReg(inst.i.rt));
|
||||||
if (branch)
|
if (branch)
|
||||||
Branch(m_regs.pc + (inst.i.imm_sext32() << 2));
|
Branch(m_regs.pc + (inst.i.imm_sext32() << 2));
|
||||||
@ -1037,6 +1055,7 @@ void Core::ExecuteInstruction()
|
|||||||
|
|
||||||
case InstructionOp::bgtz:
|
case InstructionOp::bgtz:
|
||||||
{
|
{
|
||||||
|
m_next_instruction_is_branch_delay_slot = true;
|
||||||
const bool branch = (static_cast<s32>(ReadReg(inst.i.rs)) > 0);
|
const bool branch = (static_cast<s32>(ReadReg(inst.i.rs)) > 0);
|
||||||
if (branch)
|
if (branch)
|
||||||
Branch(m_regs.pc + (inst.i.imm_sext32() << 2));
|
Branch(m_regs.pc + (inst.i.imm_sext32() << 2));
|
||||||
@ -1045,6 +1064,7 @@ void Core::ExecuteInstruction()
|
|||||||
|
|
||||||
case InstructionOp::blez:
|
case InstructionOp::blez:
|
||||||
{
|
{
|
||||||
|
m_next_instruction_is_branch_delay_slot = true;
|
||||||
const bool branch = (static_cast<s32>(ReadReg(inst.i.rs)) <= 0);
|
const bool branch = (static_cast<s32>(ReadReg(inst.i.rs)) <= 0);
|
||||||
if (branch)
|
if (branch)
|
||||||
Branch(m_regs.pc + (inst.i.imm_sext32() << 2));
|
Branch(m_regs.pc + (inst.i.imm_sext32() << 2));
|
||||||
@ -1053,6 +1073,7 @@ void Core::ExecuteInstruction()
|
|||||||
|
|
||||||
case InstructionOp::b:
|
case InstructionOp::b:
|
||||||
{
|
{
|
||||||
|
m_next_instruction_is_branch_delay_slot = true;
|
||||||
const u8 rt = static_cast<u8>(inst.i.rt.GetValue());
|
const u8 rt = static_cast<u8>(inst.i.rt.GetValue());
|
||||||
|
|
||||||
// bgez is the inverse of bltz, so simply do ltz and xor the result
|
// bgez is the inverse of bltz, so simply do ltz and xor the result
|
||||||
|
@ -87,7 +87,7 @@ private:
|
|||||||
// exceptions
|
// exceptions
|
||||||
u32 GetExceptionVector(Exception excode) const;
|
u32 GetExceptionVector(Exception excode) const;
|
||||||
void RaiseException(Exception excode);
|
void RaiseException(Exception excode);
|
||||||
void RaiseException(Exception excode, u32 EPC, bool BD, u8 CE);
|
void RaiseException(Exception excode, u32 EPC, bool BD, bool BT, u8 CE);
|
||||||
bool DispatchInterrupts();
|
bool DispatchInterrupts();
|
||||||
|
|
||||||
// flushes any load delays if present
|
// flushes any load delays if present
|
||||||
@ -123,14 +123,16 @@ private:
|
|||||||
// address of the instruction currently being executed
|
// address of the instruction currently being executed
|
||||||
Instruction m_current_instruction = {};
|
Instruction m_current_instruction = {};
|
||||||
u32 m_current_instruction_pc = 0;
|
u32 m_current_instruction_pc = 0;
|
||||||
|
bool m_current_instruction_in_branch_delay_slot = false;
|
||||||
|
bool m_current_instruction_was_branch_taken = false;
|
||||||
|
bool m_next_instruction_is_branch_delay_slot = false;
|
||||||
|
bool m_branch_was_taken = false;
|
||||||
|
|
||||||
// load delays
|
// load delays
|
||||||
Reg m_load_delay_reg = Reg::count;
|
Reg m_load_delay_reg = Reg::count;
|
||||||
u32 m_load_delay_old_value = 0;
|
u32 m_load_delay_old_value = 0;
|
||||||
Reg m_next_load_delay_reg = Reg::count;
|
Reg m_next_load_delay_reg = Reg::count;
|
||||||
u32 m_next_load_delay_old_value = 0;
|
u32 m_next_load_delay_old_value = 0;
|
||||||
bool m_in_branch_delay_slot = false;
|
|
||||||
bool m_branched = false;
|
|
||||||
|
|
||||||
u32 m_cache_control = 0;
|
u32 m_cache_control = 0;
|
||||||
|
|
||||||
|
@ -274,7 +274,7 @@ struct Cop0Registers
|
|||||||
{
|
{
|
||||||
u32 BPC; // breakpoint on execute
|
u32 BPC; // breakpoint on execute
|
||||||
u32 BDA; // breakpoint on data access
|
u32 BDA; // breakpoint on data access
|
||||||
u32 JUMPDEST; // randomly memorized jump address
|
u32 TAR; // randomly memorized jump address
|
||||||
u32 BadVaddr; // bad virtual address value
|
u32 BadVaddr; // bad virtual address value
|
||||||
u32 BDAM; // data breakpoint mask
|
u32 BDAM; // data breakpoint mask
|
||||||
u32 BPCM; // execute breakpoint mask
|
u32 BPCM; // execute breakpoint mask
|
||||||
@ -316,6 +316,7 @@ struct Cop0Registers
|
|||||||
BitField<u32, Exception, 2, 5> Excode; // which exception occurred
|
BitField<u32, Exception, 2, 5> Excode; // which exception occurred
|
||||||
BitField<u32, u8, 8, 8> Ip; // interrupt pending
|
BitField<u32, u8, 8, 8> Ip; // interrupt pending
|
||||||
BitField<u32, u8, 28, 2> CE; // coprocessor number if caused by a coprocessor
|
BitField<u32, u8, 28, 2> CE; // coprocessor number if caused by a coprocessor
|
||||||
|
BitField<u32, bool, 30, 1> BT; // exception occurred in branch delay slot, and the branch was taken
|
||||||
BitField<u32, bool, 31, 1> BD; // exception occurred in branch delay slot, but pushed IP is for branch
|
BitField<u32, bool, 31, 1> BD; // exception occurred in branch delay slot, but pushed IP is for branch
|
||||||
|
|
||||||
static constexpr u32 WRITE_MASK = 0b0000'0000'0000'0000'0000'0011'0000'0000;
|
static constexpr u32 WRITE_MASK = 0b0000'0000'0000'0000'0000'0011'0000'0000;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user