mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-02-04 21:39:54 +00:00
SPU: IRET, SN event
This commit is contained in:
parent
64ac6a59c4
commit
d2ddb9882f
@ -917,7 +917,10 @@ void spu_recompiler::BISL(spu_opcode_t op)
|
|||||||
|
|
||||||
void spu_recompiler::IRET(spu_opcode_t op)
|
void spu_recompiler::IRET(spu_opcode_t op)
|
||||||
{
|
{
|
||||||
fmt::throw_exception("Unimplemented instruction" HERE);
|
c->mov(*addr, SPU_OFF_32(srr0));
|
||||||
|
c->and_(*addr, 0x3fffc);
|
||||||
|
if (op.d || op.e) c->or_(*addr, op.e << 26 | op.d << 27); // interrupt flags neutralize jump table
|
||||||
|
c->jmp(*jt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void spu_recompiler::BISLED(spu_opcode_t op)
|
void spu_recompiler::BISLED(spu_opcode_t op)
|
||||||
|
@ -168,8 +168,6 @@ std::shared_ptr<spu_function_t> SPUDatabase::analyse(const be_t<u32>* ls, u32 en
|
|||||||
|
|
||||||
if (type == BI || type == IRET) // Branch Indirect
|
if (type == BI || type == IRET) // Branch Indirect
|
||||||
{
|
{
|
||||||
if (type == IRET) LOG_ERROR(SPU, "[0x%05x] Interrupt Return", pos);
|
|
||||||
|
|
||||||
blocks.emplace(start);
|
blocks.emplace(start);
|
||||||
start = pos + 4;
|
start = pos + 4;
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,12 @@ void spu_interpreter::set_interrupt_status(SPUThread& spu, spu_opcode_t op)
|
|||||||
{
|
{
|
||||||
spu.set_interrupt_status(false);
|
spu.set_interrupt_status(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((spu.ch_event_stat & SPU_EVENT_INTR_TEST) > SPU_EVENT_INTR_ENABLED)
|
||||||
|
{
|
||||||
|
spu.ch_event_stat &= ~SPU_EVENT_INTR_ENABLED;
|
||||||
|
spu.srr0 = std::exchange(spu.pc, -4) + 4;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -313,8 +319,8 @@ void spu_interpreter::BIZ(SPUThread& spu, spu_opcode_t op)
|
|||||||
{
|
{
|
||||||
if (spu.gpr[op.rt]._u32[3] == 0)
|
if (spu.gpr[op.rt]._u32[3] == 0)
|
||||||
{
|
{
|
||||||
set_interrupt_status(spu, op);
|
|
||||||
spu.pc = spu_branch_target(spu.gpr[op.ra]._u32[3]) - 4;
|
spu.pc = spu_branch_target(spu.gpr[op.ra]._u32[3]) - 4;
|
||||||
|
set_interrupt_status(spu, op);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -322,8 +328,8 @@ void spu_interpreter::BINZ(SPUThread& spu, spu_opcode_t op)
|
|||||||
{
|
{
|
||||||
if (spu.gpr[op.rt]._u32[3] != 0)
|
if (spu.gpr[op.rt]._u32[3] != 0)
|
||||||
{
|
{
|
||||||
set_interrupt_status(spu, op);
|
|
||||||
spu.pc = spu_branch_target(spu.gpr[op.ra]._u32[3]) - 4;
|
spu.pc = spu_branch_target(spu.gpr[op.ra]._u32[3]) - 4;
|
||||||
|
set_interrupt_status(spu, op);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,8 +337,8 @@ void spu_interpreter::BIHZ(SPUThread& spu, spu_opcode_t op)
|
|||||||
{
|
{
|
||||||
if (spu.gpr[op.rt]._u16[6] == 0)
|
if (spu.gpr[op.rt]._u16[6] == 0)
|
||||||
{
|
{
|
||||||
set_interrupt_status(spu, op);
|
|
||||||
spu.pc = spu_branch_target(spu.gpr[op.ra]._u32[3]) - 4;
|
spu.pc = spu_branch_target(spu.gpr[op.ra]._u32[3]) - 4;
|
||||||
|
set_interrupt_status(spu, op);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,8 +346,8 @@ void spu_interpreter::BIHNZ(SPUThread& spu, spu_opcode_t op)
|
|||||||
{
|
{
|
||||||
if (spu.gpr[op.rt]._u16[6] != 0)
|
if (spu.gpr[op.rt]._u16[6] != 0)
|
||||||
{
|
{
|
||||||
set_interrupt_status(spu, op);
|
|
||||||
spu.pc = spu_branch_target(spu.gpr[op.ra]._u32[3]) - 4;
|
spu.pc = spu_branch_target(spu.gpr[op.ra]._u32[3]) - 4;
|
||||||
|
set_interrupt_status(spu, op);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,21 +363,22 @@ void spu_interpreter::STQX(SPUThread& spu, spu_opcode_t op)
|
|||||||
|
|
||||||
void spu_interpreter::BI(SPUThread& spu, spu_opcode_t op)
|
void spu_interpreter::BI(SPUThread& spu, spu_opcode_t op)
|
||||||
{
|
{
|
||||||
set_interrupt_status(spu, op);
|
|
||||||
spu.pc = spu_branch_target(spu.gpr[op.ra]._u32[3]) - 4;
|
spu.pc = spu_branch_target(spu.gpr[op.ra]._u32[3]) - 4;
|
||||||
|
set_interrupt_status(spu, op);
|
||||||
}
|
}
|
||||||
|
|
||||||
void spu_interpreter::BISL(SPUThread& spu, spu_opcode_t op)
|
void spu_interpreter::BISL(SPUThread& spu, spu_opcode_t op)
|
||||||
{
|
{
|
||||||
set_interrupt_status(spu, op);
|
|
||||||
const u32 target = spu_branch_target(spu.gpr[op.ra]._u32[3]);
|
const u32 target = spu_branch_target(spu.gpr[op.ra]._u32[3]);
|
||||||
spu.gpr[op.rt] = v128::from32r(spu_branch_target(spu.pc + 4));
|
spu.gpr[op.rt] = v128::from32r(spu_branch_target(spu.pc + 4));
|
||||||
spu.pc = target - 4;
|
spu.pc = target - 4;
|
||||||
|
set_interrupt_status(spu, op);
|
||||||
}
|
}
|
||||||
|
|
||||||
void spu_interpreter::IRET(SPUThread& spu, spu_opcode_t op)
|
void spu_interpreter::IRET(SPUThread& spu, spu_opcode_t op)
|
||||||
{
|
{
|
||||||
fmt::throw_exception("Unimplemented instruction" HERE);
|
spu.pc = spu_branch_target(spu.srr0) - 4;
|
||||||
|
set_interrupt_status(spu, op);
|
||||||
}
|
}
|
||||||
|
|
||||||
void spu_interpreter::BISLED(SPUThread& spu, spu_opcode_t op)
|
void spu_interpreter::BISLED(SPUThread& spu, spu_opcode_t op)
|
||||||
|
@ -76,4 +76,10 @@ void spu_recompiler_base::enter(SPUThread& spu)
|
|||||||
}
|
}
|
||||||
|
|
||||||
spu.pc = res & 0x3fffc;
|
spu.pc = res & 0x3fffc;
|
||||||
|
|
||||||
|
if ((spu.ch_event_stat & SPU_EVENT_INTR_TEST) > SPU_EVENT_INTR_ENABLED)
|
||||||
|
{
|
||||||
|
spu.ch_event_stat &= ~SPU_EVENT_INTR_ENABLED;
|
||||||
|
spu.srr0 = std::exchange(spu.pc, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -146,6 +146,7 @@ void SPUThread::cpu_init()
|
|||||||
ch_mfc_args = {};
|
ch_mfc_args = {};
|
||||||
mfc_queue.clear();
|
mfc_queue.clear();
|
||||||
|
|
||||||
|
srr0 = 0;
|
||||||
ch_tag_mask = 0;
|
ch_tag_mask = 0;
|
||||||
ch_tag_stat.data.store({});
|
ch_tag_stat.data.store({});
|
||||||
ch_stall_stat.data.store({});
|
ch_stall_stat.data.store({});
|
||||||
@ -371,6 +372,7 @@ void SPUThread::do_dma_list_cmd(u32 cmd, spu_mfc_arg_t args)
|
|||||||
if (rec->sb & 0x8000)
|
if (rec->sb & 0x8000)
|
||||||
{
|
{
|
||||||
ch_stall_stat.set_value((1 << args.tag) | ch_stall_stat.get_value());
|
ch_stall_stat.set_value((1 << args.tag) | ch_stall_stat.get_value());
|
||||||
|
ch_event_stat |= SPU_EVENT_SN;
|
||||||
|
|
||||||
spu_mfc_arg_t stalled;
|
spu_mfc_arg_t stalled;
|
||||||
stalled.ea = (args.ea & ~0xffffffff) | (list_addr + (i + 1) * 8);
|
stalled.ea = (args.ea & ~0xffffffff) | (list_addr + (i + 1) * 8);
|
||||||
@ -418,11 +420,6 @@ void SPUThread::process_mfc_cmd(u32 cmd)
|
|||||||
|
|
||||||
case MFC_GETLLAR_CMD: // acquire reservation
|
case MFC_GETLLAR_CMD: // acquire reservation
|
||||||
{
|
{
|
||||||
if (ch_mfc_args.size != 128)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
const u32 raddr = vm::cast(ch_mfc_args.ea, HERE);
|
const u32 raddr = vm::cast(ch_mfc_args.ea, HERE);
|
||||||
|
|
||||||
vm::reservation_acquire(vm::base(offset + ch_mfc_args.lsa), raddr, 128);
|
vm::reservation_acquire(vm::base(offset + ch_mfc_args.lsa), raddr, 128);
|
||||||
@ -437,11 +434,6 @@ void SPUThread::process_mfc_cmd(u32 cmd)
|
|||||||
|
|
||||||
case MFC_PUTLLC_CMD: // store conditionally
|
case MFC_PUTLLC_CMD: // store conditionally
|
||||||
{
|
{
|
||||||
if (ch_mfc_args.size != 128)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vm::reservation_update(vm::cast(ch_mfc_args.ea, HERE), vm::base(offset + ch_mfc_args.lsa), 128))
|
if (vm::reservation_update(vm::cast(ch_mfc_args.ea, HERE), vm::base(offset + ch_mfc_args.lsa), 128))
|
||||||
{
|
{
|
||||||
if (std::exchange(last_raddr, 0) == 0)
|
if (std::exchange(last_raddr, 0) == 0)
|
||||||
@ -465,11 +457,6 @@ void SPUThread::process_mfc_cmd(u32 cmd)
|
|||||||
case MFC_PUTLLUC_CMD: // store unconditionally
|
case MFC_PUTLLUC_CMD: // store unconditionally
|
||||||
case MFC_PUTQLLUC_CMD:
|
case MFC_PUTQLLUC_CMD:
|
||||||
{
|
{
|
||||||
if (ch_mfc_args.size != 128)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
vm::reservation_op(vm::cast(ch_mfc_args.ea, HERE), 128, [this]()
|
vm::reservation_op(vm::cast(ch_mfc_args.ea, HERE), 128, [this]()
|
||||||
{
|
{
|
||||||
std::memcpy(vm::base_priv(vm::cast(ch_mfc_args.ea, HERE)), vm::base(offset + ch_mfc_args.lsa), 128);
|
std::memcpy(vm::base_priv(vm::cast(ch_mfc_args.ea, HERE)), vm::base(offset + ch_mfc_args.lsa), 128);
|
||||||
@ -512,9 +499,12 @@ u32 SPUThread::get_events(bool waiting)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SPU Decrementer Event
|
// SPU Decrementer Event
|
||||||
if ((ch_dec_value - (get_timebased_time() - ch_dec_start_timestamp)) >> 31)
|
if (!ch_dec_value || (ch_dec_value - (get_timebased_time() - ch_dec_start_timestamp)) >> 31)
|
||||||
{
|
{
|
||||||
ch_event_stat |= SPU_EVENT_TM;
|
if ((ch_event_stat & SPU_EVENT_TM) == 0)
|
||||||
|
{
|
||||||
|
ch_event_stat |= SPU_EVENT_TM;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize waiting
|
// initialize waiting
|
||||||
@ -562,7 +552,7 @@ void SPUThread::set_interrupt_status(bool enable)
|
|||||||
if (enable)
|
if (enable)
|
||||||
{
|
{
|
||||||
// detect enabling interrupts with events masked
|
// detect enabling interrupts with events masked
|
||||||
if (u32 mask = ch_event_mask)
|
if (u32 mask = ch_event_mask & ~SPU_EVENT_INTR_IMPLEMENTED)
|
||||||
{
|
{
|
||||||
fmt::throw_exception("SPU Interrupts not implemented (mask=0x%x)" HERE, mask);
|
fmt::throw_exception("SPU Interrupts not implemented (mask=0x%x)" HERE, mask);
|
||||||
}
|
}
|
||||||
@ -617,9 +607,11 @@ bool SPUThread::get_ch_value(u32 ch, u32& out)
|
|||||||
|
|
||||||
switch (ch)
|
switch (ch)
|
||||||
{
|
{
|
||||||
//case SPU_RdSRR0:
|
case SPU_RdSRR0:
|
||||||
// value = SRR0;
|
{
|
||||||
// break;
|
out = srr0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
case SPU_RdInMbox:
|
case SPU_RdInMbox:
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
@ -738,9 +730,12 @@ bool SPUThread::set_ch_value(u32 ch, u32 value)
|
|||||||
|
|
||||||
switch (ch)
|
switch (ch)
|
||||||
{
|
{
|
||||||
//case SPU_WrSRR0:
|
case SPU_WrSRR0:
|
||||||
// SRR0 = value & 0x3FFFC; //LSLR & ~3
|
{
|
||||||
// break;
|
srr0 = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case SPU_WrOutIntrMbox:
|
case SPU_WrOutIntrMbox:
|
||||||
{
|
{
|
||||||
if (offset >= RAW_SPU_BASE_ADDR)
|
if (offset >= RAW_SPU_BASE_ADDR)
|
||||||
@ -1013,7 +1008,7 @@ bool SPUThread::set_ch_value(u32 ch, u32 value)
|
|||||||
case SPU_WrEventMask:
|
case SPU_WrEventMask:
|
||||||
{
|
{
|
||||||
// detect masking events with enabled interrupt status
|
// detect masking events with enabled interrupt status
|
||||||
if (value && ch_event_stat & SPU_EVENT_INTR_ENABLED)
|
if (value & ~SPU_EVENT_INTR_IMPLEMENTED && ch_event_stat & SPU_EVENT_INTR_ENABLED)
|
||||||
{
|
{
|
||||||
fmt::throw_exception("SPU Interrupts not implemented (mask=0x%x)" HERE, value);
|
fmt::throw_exception("SPU Interrupts not implemented (mask=0x%x)" HERE, value);
|
||||||
}
|
}
|
||||||
|
@ -63,11 +63,14 @@ enum : u32
|
|||||||
SPU_EVENT_SN = 0x2, // MFC List Command stall-and-notify event
|
SPU_EVENT_SN = 0x2, // MFC List Command stall-and-notify event
|
||||||
SPU_EVENT_TG = 0x1, // MFC Tag Group status update event
|
SPU_EVENT_TG = 0x1, // MFC Tag Group status update event
|
||||||
|
|
||||||
SPU_EVENT_IMPLEMENTED = SPU_EVENT_LR | SPU_EVENT_TM, // Mask of implemented events
|
SPU_EVENT_IMPLEMENTED = SPU_EVENT_LR | SPU_EVENT_TM | SPU_EVENT_SN, // Mask of implemented events
|
||||||
|
SPU_EVENT_INTR_IMPLEMENTED = SPU_EVENT_SN,
|
||||||
|
|
||||||
SPU_EVENT_WAITING = 0x80000000, // Originally unused, set when SPU thread starts waiting on ch_event_stat
|
SPU_EVENT_WAITING = 0x80000000, // Originally unused, set when SPU thread starts waiting on ch_event_stat
|
||||||
//SPU_EVENT_AVAILABLE = 0x40000000, // Originally unused, channel count of the SPU_RdEventStat channel
|
//SPU_EVENT_AVAILABLE = 0x40000000, // Originally unused, channel count of the SPU_RdEventStat channel
|
||||||
SPU_EVENT_INTR_ENABLED = 0x20000000, // Originally unused, represents "SPU Interrupts Enabled" status
|
SPU_EVENT_INTR_ENABLED = 0x20000000, // Originally unused, represents "SPU Interrupts Enabled" status
|
||||||
|
|
||||||
|
SPU_EVENT_INTR_TEST = SPU_EVENT_INTR_ENABLED | SPU_EVENT_INTR_IMPLEMENTED
|
||||||
};
|
};
|
||||||
|
|
||||||
// SPU Class 0 Interrupts
|
// SPU Class 0 Interrupts
|
||||||
@ -516,6 +519,7 @@ public:
|
|||||||
|
|
||||||
std::vector<std::pair<u32, spu_mfc_arg_t>> mfc_queue; // Only used for stalled list transfers
|
std::vector<std::pair<u32, spu_mfc_arg_t>> mfc_queue; // Only used for stalled list transfers
|
||||||
|
|
||||||
|
u32 srr0;
|
||||||
u32 ch_tag_mask;
|
u32 ch_tag_mask;
|
||||||
spu_channel_t ch_tag_stat;
|
spu_channel_t ch_tag_stat;
|
||||||
spu_channel_t ch_stall_stat;
|
spu_channel_t ch_stall_stat;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user