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"
reservation_struct reservation;
CPUThread* GetCurrentCPUThread()
{
return (CPUThread*)GetCurrentNamedThread();

View file

@ -3,26 +3,6 @@
#include "Emu/CPU/CPUDecoder.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
{
CPU_THREAD_PPU,

View file

@ -309,9 +309,12 @@ union SPU_SNRConfig_hdr
class SPUThread : public PPCThread
{
public:
SPU_GPR_hdr GPR[128]; //General-Purpose Registers
SPU_GPR_hdr GPR[128]; // General-Purpose Registers
//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
EventManager SPUQs; // SPU Queue Mapping
@ -796,83 +799,90 @@ public:
if (op == MFC_GETLLAR_CMD) // get reservation
{
SMutexLockerR lock(reservation.mutex);
reservation.owner = lock.tid;
reservation.addr = ea;
if (R_ADDR)
{
m_events |= SPU_EVENT_LR;
}
R_ADDR = ea;
for (u32 i = 0; i < 16; i++)
{
reservation.data[i] = *(u64*)&Memory[(u32)ea + i * 8];
*(u64*)&Memory[dmac.ls_offset + lsa + i * 8] = reservation.data[i];
R_DATA[i] = *(u64*)&Memory[R_ADDR + i * 8];
*(u64*)&Memory[dmac.ls_offset + lsa + i * 8] = R_DATA[i];
}
MFCArgs.AtomicStat.PushUncond(MFC_GETLLAR_SUCCESS);
}
else if (op == MFC_PUTLLC_CMD) // store conditional
{
SMutexLockerR lock(reservation.mutex);
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_SUCCESS);
if (reservation.owner == lock.tid) // succeeded
if (R_ADDR == ea)
{
if (reservation.addr == ea)
u32 changed = 0, mask = 0;
u64 buf[16];
for (u32 i = 0; i < 16; i++)
{
for (u32 i = 0; i < 16; i++)
buf[i] = *(u64*)&Memory[dmac.ls_offset + lsa + i * 8];
if (buf[i] != R_DATA[i])
{
if (*(u64*)&Memory[reservation.addr + i * 8] != reservation.data[i])
changed++;
mask |= (0x3 << (i * 2));
if (*(u64*)&Memory[R_ADDR + i * 8] != R_DATA[i])
{
m_events |= SPU_EVENT_LR;
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE);
reservation.clear();
R_ADDR = 0;
return;
}
}
}
u32 changed = 0, mask = 0;
for (u32 i = 0; i < 16; i++)
for (u32 i = 0; i < 16; i++)
{
if (buf[i] != R_DATA[i])
{
u64 buf = *(u64*)&Memory[dmac.ls_offset + lsa + i * 8];
if (buf != reservation.data[i])
if (InterlockedCompareExchange64((volatile long long*)(Memory + (ea + i * 8)), buf[i], R_DATA[i]) != R_DATA[i])
{
changed++;
mask |= (0x3 << (i * 2));
m_events |= SPU_EVENT_LR;
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE);
if (InterlockedCompareExchange64((volatile long long*)(Memory + ((u32)ea + i * 8)), buf, reservation.data[i]) != reservation.data[i])
if (changed > 1)
{
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE);
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)",
changed, mask, op, cmd, lsa, ea, tag, size);
Emu.Pause();
}
break;
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);
Emu.Pause();
}
break;
}
}
}
else
if (changed > 1)
{
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE);
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);
}
reservation.clear();
}
else // failed
else
{
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE);
}
R_ADDR = 0;
}
else // store unconditional
{
SMutexLockerR lock(reservation.mutex);
if (R_ADDR)
{
m_events |= SPU_EVENT_LR;
}
ProcessCmd(MFC_PUT_CMD, tag, lsa, ea, 128);
if (op == MFC_PUTLLUC_CMD)
{
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLUC_SUCCESS);
}
if (reservation.addr == ea)
{
reservation.clear();
}
R_ADDR = 0;
}
}
break;
@ -888,24 +898,15 @@ public:
{
// 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[R_ADDR + i * 8] != R_DATA[i])
{
if (*(u64*)&Memory[reservation.addr + i * 8] != reservation.data[i])
{
m_events |= SPU_EVENT_LR;
reservation.clear(); // ???
break;
}
m_events |= SPU_EVENT_LR;
R_ADDR = 0;
break;
}
}
else
{
m_events |= SPU_EVENT_LR; // ???
}
}
return (m_events & m_event_mask) != 0;
@ -1338,6 +1339,13 @@ public:
break;
}
case SPU_RdMachStat:
{
v = 1; // hack (not isolated, interrupts enabled)
// TODO: check value
break;
}
default:
{
LOG_ERROR(Log::SPU, "%s error: unknown/illegal channel (%d [%s]).", __FUNCTION__, ch, spu_ch_name[ch]);