Reservation global struct removed

It wasn't solving anything, unfortunately.
This commit is contained in:
Nekotekina 2014-08-22 01:37:45 +04:00
parent 184007e1e0
commit a169c5bcac
3 changed files with 61 additions and 75 deletions

View file

@ -9,8 +9,6 @@
#include "CPUThread.h" #include "CPUThread.h"
reservation_struct reservation;
CPUThread* GetCurrentCPUThread() CPUThread* GetCurrentCPUThread()
{ {
return (CPUThread*)GetCurrentNamedThread(); return (CPUThread*)GetCurrentNamedThread();

View file

@ -3,26 +3,6 @@
#include "Emu/CPU/CPUDecoder.h" #include "Emu/CPU/CPUDecoder.h"
#include "Utilities/SMutex.h" #include "Utilities/SMutex.h"
typedef SMutexBase<u32, 0, 0xffffffff, /* busy wait: specify nullptr */ SM_Sleep> SMutexR;
typedef SMutexLockerBase<SMutexR, u32, SM_GetCurrentCPUThreadId> SMutexLockerR;
struct reservation_struct
{
SMutexR mutex; // mutex for updating reservation_owner and data
// std::mutex doesn't work because it probably wakes up waiting threads in the most unwanted order
// and doesn't give a chance to finish some work before losing the reservation
u32 owner; // id of thread that got reservation
u64 addr;
u64 data[16];
__forceinline void clear()
{
owner = 0;
}
};
extern reservation_struct reservation;
enum CPUThreadType :unsigned char enum CPUThreadType :unsigned char
{ {
CPU_THREAD_PPU, CPU_THREAD_PPU,

View file

@ -309,9 +309,12 @@ union SPU_SNRConfig_hdr
class SPUThread : public PPCThread class SPUThread : public PPCThread
{ {
public: public:
SPU_GPR_hdr GPR[128]; //General-Purpose Registers SPU_GPR_hdr GPR[128]; // General-Purpose Registers
//FPSCR FPSCR; //FPSCR FPSCR;
SPU_SNRConfig_hdr cfg; //Signal Notification Registers Configuration (OR-mode enabled: 0x1 for SNR1, 0x2 for SNR2) SPU_SNRConfig_hdr cfg; // Signal Notification Registers Configuration (OR-mode enabled: 0x1 for SNR1, 0x2 for SNR2)
u64 R_ADDR; // reservation address
u64 R_DATA[16]; // lock line data (BE)
EventPort SPUPs[64]; // SPU Thread Event Ports EventPort SPUPs[64]; // SPU Thread Event Ports
EventManager SPUQs; // SPU Queue Mapping EventManager SPUQs; // SPU Queue Mapping
@ -796,51 +799,56 @@ public:
if (op == MFC_GETLLAR_CMD) // get reservation if (op == MFC_GETLLAR_CMD) // get reservation
{ {
SMutexLockerR lock(reservation.mutex); if (R_ADDR)
reservation.owner = lock.tid; {
reservation.addr = ea; m_events |= SPU_EVENT_LR;
}
R_ADDR = ea;
for (u32 i = 0; i < 16; i++) for (u32 i = 0; i < 16; i++)
{ {
reservation.data[i] = *(u64*)&Memory[(u32)ea + i * 8]; R_DATA[i] = *(u64*)&Memory[R_ADDR + i * 8];
*(u64*)&Memory[dmac.ls_offset + lsa + i * 8] = reservation.data[i]; *(u64*)&Memory[dmac.ls_offset + lsa + i * 8] = R_DATA[i];
} }
MFCArgs.AtomicStat.PushUncond(MFC_GETLLAR_SUCCESS); MFCArgs.AtomicStat.PushUncond(MFC_GETLLAR_SUCCESS);
} }
else if (op == MFC_PUTLLC_CMD) // store conditional else if (op == MFC_PUTLLC_CMD) // store conditional
{ {
SMutexLockerR lock(reservation.mutex);
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_SUCCESS); MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_SUCCESS);
if (reservation.owner == lock.tid) // succeeded if (R_ADDR == ea)
{ {
if (reservation.addr == ea)
{
for (u32 i = 0; i < 16; i++)
{
if (*(u64*)&Memory[reservation.addr + i * 8] != reservation.data[i])
{
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE);
reservation.clear();
return;
}
}
u32 changed = 0, mask = 0; u32 changed = 0, mask = 0;
u64 buf[16];
for (u32 i = 0; i < 16; i++) for (u32 i = 0; i < 16; i++)
{ {
u64 buf = *(u64*)&Memory[dmac.ls_offset + lsa + i * 8]; buf[i] = *(u64*)&Memory[dmac.ls_offset + lsa + i * 8];
if (buf != reservation.data[i]) if (buf[i] != R_DATA[i])
{ {
changed++; changed++;
mask |= (0x3 << (i * 2)); mask |= (0x3 << (i * 2));
if (*(u64*)&Memory[R_ADDR + i * 8] != R_DATA[i])
if (InterlockedCompareExchange64((volatile long long*)(Memory + ((u32)ea + i * 8)), buf, reservation.data[i]) != reservation.data[i])
{ {
m_events |= SPU_EVENT_LR;
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE);
R_ADDR = 0;
return;
}
}
}
for (u32 i = 0; i < 16; i++)
{
if (buf[i] != R_DATA[i])
{
if (InterlockedCompareExchange64((volatile long long*)(Memory + (ea + i * 8)), buf[i], R_DATA[i]) != R_DATA[i])
{
m_events |= SPU_EVENT_LR;
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE); MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE);
if (changed > 1) if (changed > 1)
{ {
LOG_ERROR(Log::SPU, "MFC_PUTLLC_CMD: Reservation Error: impossibru (~ 8x%d (mask=0x%x)) (opcode=0x%x, cmd=0x%x, lsa = 0x%x, ea = 0x%llx, tag = 0x%x, size = 0x%x)", LOG_ERROR(Log::SPU, "MFC_PUTLLC_CMD: Memory corrupted (~x%d (mask=0x%x)) (opcode=0x%x, cmd=0x%x, lsa = 0x%x, ea = 0x%llx, tag = 0x%x, size = 0x%x)",
changed, mask, op, cmd, lsa, ea, tag, size); changed, mask, op, cmd, lsa, ea, tag, size);
Emu.Pause(); Emu.Pause();
} }
@ -849,30 +857,32 @@ public:
} }
} }
} }
if (changed > 1)
{
LOG_WARNING(Log::SPU, "MFC_PUTLLC_CMD: Reservation impossibru (~x%d (mask=0x%x)) (opcode=0x%x, cmd=0x%x, lsa = 0x%x, ea = 0x%llx, tag = 0x%x, size = 0x%x)",
changed, mask, op, cmd, lsa, ea, tag, size);
}
} }
else else
{ {
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE); MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE);
} }
reservation.clear(); R_ADDR = 0;
}
else // failed
{
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE);
}
} }
else // store unconditional else // store unconditional
{ {
SMutexLockerR lock(reservation.mutex); if (R_ADDR)
{
m_events |= SPU_EVENT_LR;
}
ProcessCmd(MFC_PUT_CMD, tag, lsa, ea, 128); ProcessCmd(MFC_PUT_CMD, tag, lsa, ea, 128);
if (op == MFC_PUTLLUC_CMD) if (op == MFC_PUTLLUC_CMD)
{ {
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLUC_SUCCESS); MFCArgs.AtomicStat.PushUncond(MFC_PUTLLUC_SUCCESS);
} }
if (reservation.addr == ea) R_ADDR = 0;
{
reservation.clear();
}
} }
} }
break; break;
@ -887,26 +897,17 @@ public:
bool CheckEvents() // checks events bool CheckEvents() // checks events
{ {
// SPU_EVENT_LR: // SPU_EVENT_LR:
{
SMutexLockerR lock(reservation.mutex);
if (reservation.owner == lock.tid)
{ {
for (u32 i = 0; i < 16; i++) for (u32 i = 0; i < 16; i++)
{ {
if (*(u64*)&Memory[reservation.addr + i * 8] != reservation.data[i]) if (*(u64*)&Memory[R_ADDR + i * 8] != R_DATA[i])
{ {
m_events |= SPU_EVENT_LR; m_events |= SPU_EVENT_LR;
reservation.clear(); // ??? R_ADDR = 0;
break; break;
} }
} }
} }
else
{
m_events |= SPU_EVENT_LR; // ???
}
}
return (m_events & m_event_mask) != 0; return (m_events & m_event_mask) != 0;
} }
@ -1338,6 +1339,13 @@ public:
break; break;
} }
case SPU_RdMachStat:
{
v = 1; // hack (not isolated, interrupts enabled)
// TODO: check value
break;
}
default: default:
{ {
LOG_ERROR(Log::SPU, "%s error: unknown/illegal channel (%d [%s]).", __FUNCTION__, ch, spu_ch_name[ch]); LOG_ERROR(Log::SPU, "%s error: unknown/illegal channel (%d [%s]).", __FUNCTION__, ch, spu_ch_name[ch]);