2012-11-15 00:39:56 +01:00
|
|
|
#pragma once
|
2014-08-22 23:15:02 +02:00
|
|
|
#include "PPCThread.h"
|
2014-07-06 18:05:52 +02:00
|
|
|
#include "Emu/Event.h"
|
2013-08-03 11:40:03 +02:00
|
|
|
#include "MFC.h"
|
2014-01-14 20:03:48 +01:00
|
|
|
|
2012-11-15 00:39:56 +01:00
|
|
|
enum SPUchannels
|
|
|
|
|
{
|
2014-04-04 15:25:38 +02:00
|
|
|
SPU_RdEventStat = 0, //Read event status with mask applied
|
|
|
|
|
SPU_WrEventMask = 1, //Write event mask
|
|
|
|
|
SPU_WrEventAck = 2, //Write end of event processing
|
|
|
|
|
SPU_RdSigNotify1 = 3, //Signal notification 1
|
|
|
|
|
SPU_RdSigNotify2 = 4, //Signal notification 2
|
|
|
|
|
SPU_WrDec = 7, //Write decrementer count
|
|
|
|
|
SPU_RdDec = 8, //Read decrementer count
|
|
|
|
|
SPU_RdEventMask = 11, //Read event mask
|
|
|
|
|
SPU_RdMachStat = 13, //Read SPU run status
|
|
|
|
|
SPU_WrSRR0 = 14, //Write SPU machine state save/restore register 0 (SRR0)
|
|
|
|
|
SPU_RdSRR0 = 15, //Read SPU machine state save/restore register 0 (SRR0)
|
|
|
|
|
SPU_WrOutMbox = 28, //Write outbound mailbox contents
|
|
|
|
|
SPU_RdInMbox = 29, //Read inbound mailbox contents
|
|
|
|
|
SPU_WrOutIntrMbox = 30, //Write outbound interrupt mailbox contents (interrupting PPU)
|
2012-11-15 00:39:56 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum MFCchannels
|
|
|
|
|
{
|
2014-04-04 15:25:38 +02:00
|
|
|
MFC_WrMSSyncReq = 9, //Write multisource synchronization request
|
|
|
|
|
MFC_RdTagMask = 12, //Read tag mask
|
|
|
|
|
MFC_LSA = 16, //Write local memory address command parameter
|
|
|
|
|
MFC_EAH = 17, //Write high order DMA effective address command parameter
|
|
|
|
|
MFC_EAL = 18, //Write low order DMA effective address command parameter
|
|
|
|
|
MFC_Size = 19, //Write DMA transfer size command parameter
|
|
|
|
|
MFC_TagID = 20, //Write tag identifier command parameter
|
|
|
|
|
MFC_Cmd = 21, //Write and enqueue DMA command with associated class ID
|
|
|
|
|
MFC_WrTagMask = 22, //Write tag mask
|
|
|
|
|
MFC_WrTagUpdate = 23, //Write request for conditional or unconditional tag status update
|
|
|
|
|
MFC_RdTagStat = 24, //Read tag status with mask applied
|
|
|
|
|
MFC_RdListStallStat = 25, //Read DMA list stall-and-notify status
|
|
|
|
|
MFC_WrListStallAck = 26, //Write DMA list stall-and-notify acknowledge
|
|
|
|
|
MFC_RdAtomicStat = 27, //Read completion status of last completed immediate MFC atomic update command
|
2012-11-15 00:39:56 +01:00
|
|
|
};
|
|
|
|
|
|
2014-08-21 00:12:56 +02:00
|
|
|
enum SPUEvents
|
|
|
|
|
{
|
|
|
|
|
SPU_EVENT_MS = 0x1000, // multisource synchronization event
|
|
|
|
|
SPU_EVENT_A = 0x800, // privileged attention event
|
|
|
|
|
SPU_EVENT_LR = 0x400, // lock line reservation lost event
|
|
|
|
|
SPU_EVENT_S1 = 0x200, // signal notification register 1 available
|
|
|
|
|
SPU_EVENT_S2 = 0x100, // signal notification register 2 available
|
|
|
|
|
SPU_EVENT_LE = 0x80, // SPU outbound mailbox available
|
|
|
|
|
SPU_EVENT_ME = 0x40, // SPU outbound interrupt mailbox available
|
|
|
|
|
SPU_EVENT_TM = 0x20, // SPU decrementer became negative (?)
|
|
|
|
|
SPU_EVENT_MB = 0x10, // SPU inbound mailbox available
|
|
|
|
|
SPU_EVENT_QV = 0x4, // MFC SPU command queue available
|
|
|
|
|
SPU_EVENT_SN = 0x2, // MFC list command stall-and-notify event
|
|
|
|
|
SPU_EVENT_TG = 0x1, // MFC tag-group status update event
|
|
|
|
|
|
|
|
|
|
SPU_EVENT_IMPLEMENTED = SPU_EVENT_LR,
|
|
|
|
|
};
|
|
|
|
|
|
2013-07-12 14:42:17 +02:00
|
|
|
enum
|
|
|
|
|
{
|
2014-04-04 15:25:38 +02:00
|
|
|
SPU_RUNCNTL_STOP = 0,
|
|
|
|
|
SPU_RUNCNTL_RUNNABLE = 1,
|
2013-07-12 14:42:17 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum
|
|
|
|
|
{
|
2014-04-04 15:25:38 +02:00
|
|
|
SPU_STATUS_STOPPED = 0x0,
|
|
|
|
|
SPU_STATUS_RUNNING = 0x1,
|
|
|
|
|
SPU_STATUS_STOPPED_BY_STOP = 0x2,
|
|
|
|
|
SPU_STATUS_STOPPED_BY_HALT = 0x4,
|
|
|
|
|
SPU_STATUS_WAITING_FOR_CHANNEL = 0x8,
|
|
|
|
|
SPU_STATUS_SINGLE_STEP = 0x10,
|
2013-07-12 14:42:17 +02:00
|
|
|
};
|
|
|
|
|
|
2014-03-15 21:46:53 +01:00
|
|
|
enum : u32
|
|
|
|
|
{
|
2014-04-04 15:25:38 +02:00
|
|
|
SYS_SPU_THREAD_BASE_LOW = 0xf0000000,
|
2014-03-15 21:46:53 +01:00
|
|
|
SYS_SPU_THREAD_BASE_MASK = 0xfffffff,
|
2014-04-04 15:25:38 +02:00
|
|
|
SYS_SPU_THREAD_OFFSET = 0x00100000,
|
|
|
|
|
SYS_SPU_THREAD_SNR1 = 0x05400c,
|
|
|
|
|
SYS_SPU_THREAD_SNR2 = 0x05C00c,
|
2014-03-15 21:46:53 +01:00
|
|
|
};
|
|
|
|
|
|
2014-06-25 00:16:44 +02:00
|
|
|
enum
|
|
|
|
|
{
|
|
|
|
|
MFC_LSA_offs = 0x3004,
|
|
|
|
|
MFC_EAH_offs = 0x3008,
|
|
|
|
|
MFC_EAL_offs = 0x300C,
|
|
|
|
|
MFC_Size_Tag_offs = 0x3010,
|
|
|
|
|
MFC_Class_CMD_offs = 0x3014,
|
|
|
|
|
MFC_CMDStatus_offs = 0x3014,
|
|
|
|
|
MFC_QStatus_offs = 0x3104,
|
|
|
|
|
Prxy_QueryType_offs = 0x3204,
|
|
|
|
|
Prxy_QueryMask_offs = 0x321C,
|
|
|
|
|
Prxy_TagStatus_offs = 0x322C,
|
|
|
|
|
SPU_Out_MBox_offs = 0x4004,
|
|
|
|
|
SPU_In_MBox_offs = 0x400C,
|
|
|
|
|
SPU_MBox_Status_offs = 0x4014,
|
|
|
|
|
SPU_RunCntl_offs = 0x401C,
|
|
|
|
|
SPU_Status_offs = 0x4024,
|
|
|
|
|
SPU_NPC_offs = 0x4034,
|
|
|
|
|
SPU_RdSigNotify1_offs = 0x1400C,
|
|
|
|
|
SPU_RdSigNotify2_offs = 0x1C00C,
|
|
|
|
|
};
|
|
|
|
|
|
2013-11-09 16:41:56 +01:00
|
|
|
//Floating point status and control register. Unsure if this is one of the GPRs or SPRs
|
|
|
|
|
//Is 128 bits, but bits 0-19, 24-28, 32-49, 56-60, 64-81, 88-92, 96-115, 120-124 are unused
|
|
|
|
|
class FPSCR
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
u64 low;
|
|
|
|
|
u64 hi;
|
|
|
|
|
|
|
|
|
|
FPSCR() {}
|
|
|
|
|
|
2014-04-01 02:33:55 +02:00
|
|
|
std::string ToString() const
|
2013-11-09 16:41:56 +01:00
|
|
|
{
|
2014-04-01 02:33:55 +02:00
|
|
|
return "FPSCR writer not yet implemented"; //fmt::Format("%08x%08x%08x%08x", _u32[3], _u32[2], _u32[1], _u32[0]);
|
2013-11-09 16:41:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Reset()
|
|
|
|
|
{
|
|
|
|
|
memset(this, 0, sizeof(*this));
|
|
|
|
|
}
|
|
|
|
|
//slice -> 0 - 1 (4 slices total, only two have rounding)
|
|
|
|
|
//0 -> round even
|
|
|
|
|
//1 -> round towards zero (truncate)
|
|
|
|
|
//2 -> round towards positive inf
|
|
|
|
|
//3 -> round towards neg inf
|
|
|
|
|
void setSliceRounding(u8 slice, u8 roundTo)
|
|
|
|
|
{
|
|
|
|
|
u64 mask = roundTo;
|
|
|
|
|
switch(slice)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
mask = mask << 20;
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
mask = mask << 22;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//rounding is located in the low end of the FPSCR
|
|
|
|
|
this->low = this->low & mask;
|
|
|
|
|
}
|
|
|
|
|
//Slice 0 or 1
|
2014-08-31 22:12:09 +02:00
|
|
|
u8 checkSliceRounding(u8 slice) const
|
2013-11-09 16:41:56 +01:00
|
|
|
{
|
|
|
|
|
switch(slice)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
return this->low >> 20 & 0x3;
|
|
|
|
|
|
|
|
|
|
case 1:
|
|
|
|
|
return this->low >> 22 & 0x3;
|
2014-04-28 05:34:47 +02:00
|
|
|
|
|
|
|
|
default:
|
2014-08-22 23:15:02 +02:00
|
|
|
throw fmt::Format("Unexpected slice value in FPSCR::checkSliceRounding(): %d", slice);
|
2014-04-28 05:34:47 +02:00
|
|
|
return 0;
|
2013-11-09 16:41:56 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//Single Precision Exception Flags (all 3 slices)
|
|
|
|
|
//slice -> slice number (0-3)
|
|
|
|
|
//exception: 1 -> Overflow 2 -> Underflow 4-> Diff (could be IE^3 non compliant)
|
|
|
|
|
void setSinglePrecisionExceptionFlags(u8 slice, u8 exception)
|
|
|
|
|
{
|
|
|
|
|
u64 mask = exception;
|
|
|
|
|
switch(slice)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
|
|
|
|
mask = mask << 29;
|
|
|
|
|
this->low = this->low & mask;
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
mask = mask << 61;
|
|
|
|
|
this->low = this->low & mask;
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
mask = mask << 29;
|
|
|
|
|
this->hi = this->hi & mask;
|
|
|
|
|
break;
|
|
|
|
|
case 3:
|
|
|
|
|
mask = mask << 61;
|
|
|
|
|
this->hi = this->hi & mask;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
2013-12-22 18:40:50 +01:00
|
|
|
union SPU_SNRConfig_hdr
|
|
|
|
|
{
|
|
|
|
|
u64 value;
|
|
|
|
|
|
|
|
|
|
SPU_SNRConfig_hdr() {}
|
|
|
|
|
|
2014-04-01 02:33:55 +02:00
|
|
|
std::string ToString() const
|
2013-12-22 18:40:50 +01:00
|
|
|
{
|
2014-04-01 02:33:55 +02:00
|
|
|
return fmt::Format("%01x", value);
|
2013-12-22 18:40:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Reset()
|
|
|
|
|
{
|
|
|
|
|
memset(this, 0, sizeof(*this));
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2014-08-22 23:15:02 +02:00
|
|
|
struct SpuGroupInfo;
|
|
|
|
|
|
2012-11-15 00:39:56 +01:00
|
|
|
class SPUThread : public PPCThread
|
|
|
|
|
{
|
|
|
|
|
public:
|
2014-09-06 18:30:13 +02:00
|
|
|
u128 GPR[128]; // General-Purpose Registers
|
2014-07-11 11:39:51 +02:00
|
|
|
//FPSCR FPSCR;
|
2014-08-21 23:37:45 +02:00
|
|
|
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)
|
2013-11-03 20:23:16 +01:00
|
|
|
|
2014-02-22 01:26:50 +01:00
|
|
|
EventPort SPUPs[64]; // SPU Thread Event Ports
|
|
|
|
|
EventManager SPUQs; // SPU Queue Mapping
|
2014-03-15 21:46:53 +01:00
|
|
|
SpuGroupInfo* group; // associated SPU Thread Group (null for raw spu)
|
2014-02-22 01:26:50 +01:00
|
|
|
|
2014-07-05 21:23:34 +02:00
|
|
|
u64 m_dec_start; // timestamp of writing decrementer value
|
|
|
|
|
u32 m_dec_value; // written decrementer value
|
|
|
|
|
|
2014-08-21 00:12:56 +02:00
|
|
|
u32 m_event_mask;
|
|
|
|
|
u32 m_events;
|
|
|
|
|
|
2014-06-23 03:03:16 +02:00
|
|
|
struct IntrTag
|
|
|
|
|
{
|
|
|
|
|
u32 enabled; // 1 == true
|
|
|
|
|
u32 thread; // established interrupt PPU thread
|
|
|
|
|
u64 mask;
|
|
|
|
|
u64 stat;
|
|
|
|
|
|
|
|
|
|
IntrTag()
|
|
|
|
|
: enabled(0)
|
|
|
|
|
, thread(0)
|
|
|
|
|
, mask(0)
|
|
|
|
|
, stat(0)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
} m_intrtag[3];
|
|
|
|
|
|
2013-11-03 20:23:16 +01:00
|
|
|
template<size_t _max_count>
|
|
|
|
|
class Channel
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
static const size_t max_count = _max_count;
|
2014-06-02 14:08:32 +02:00
|
|
|
|
2014-04-07 15:06:13 +02:00
|
|
|
private:
|
2013-12-25 18:28:10 +01:00
|
|
|
union _CRT_ALIGN(8) {
|
|
|
|
|
struct {
|
2013-12-27 12:35:08 +01:00
|
|
|
volatile u32 m_index;
|
2013-12-25 18:28:10 +01:00
|
|
|
u32 m_value[max_count];
|
|
|
|
|
};
|
2013-12-27 12:35:08 +01:00
|
|
|
volatile u64 m_indval;
|
2013-12-25 18:28:10 +01:00
|
|
|
};
|
2014-01-14 20:03:48 +01:00
|
|
|
std::mutex m_lock;
|
2013-11-03 20:23:16 +01:00
|
|
|
|
2014-04-07 15:06:13 +02:00
|
|
|
public:
|
2013-11-03 20:23:16 +01:00
|
|
|
Channel()
|
|
|
|
|
{
|
|
|
|
|
Init();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Init()
|
|
|
|
|
{
|
2014-07-14 11:24:10 +02:00
|
|
|
m_indval = 0;
|
2013-11-03 20:23:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
__forceinline bool Pop(u32& res)
|
|
|
|
|
{
|
2014-06-02 14:08:32 +02:00
|
|
|
if (max_count > 1)
|
2013-12-10 23:58:11 +01:00
|
|
|
{
|
2014-01-14 20:03:48 +01:00
|
|
|
std::lock_guard<std::mutex> lock(m_lock);
|
2013-12-25 18:28:10 +01:00
|
|
|
if(!m_index)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2014-02-22 01:26:50 +01:00
|
|
|
res = m_value[0];
|
2014-04-16 13:09:06 +02:00
|
|
|
if (max_count > 1) for (u32 i = 1; i < max_count; i++) // FIFO
|
2014-02-22 01:26:50 +01:00
|
|
|
{
|
|
|
|
|
m_value[i-1] = m_value[i];
|
|
|
|
|
}
|
|
|
|
|
m_value[max_count-1] = 0;
|
|
|
|
|
m_index--;
|
2013-12-25 18:28:10 +01:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{ //lock-free
|
2014-01-14 20:03:48 +01:00
|
|
|
if ((m_indval & 0xffffffff) == 0)
|
2013-12-25 18:28:10 +01:00
|
|
|
return false;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
res = (m_indval >> 32);
|
|
|
|
|
m_indval = 0;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2013-12-10 23:58:11 +01:00
|
|
|
}
|
2013-11-03 20:23:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
__forceinline bool Push(u32 value)
|
|
|
|
|
{
|
2014-06-02 14:08:32 +02:00
|
|
|
if (max_count > 1)
|
2013-12-10 23:58:11 +01:00
|
|
|
{
|
2014-01-14 20:03:48 +01:00
|
|
|
std::lock_guard<std::mutex> lock(m_lock);
|
2013-12-25 18:28:10 +01:00
|
|
|
if(m_index >= max_count)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
m_value[m_index++] = value;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{ //lock-free
|
2014-01-14 20:03:48 +01:00
|
|
|
if (m_indval & 0xffffffff)
|
2013-12-25 18:28:10 +01:00
|
|
|
return false;
|
|
|
|
|
else
|
|
|
|
|
{
|
2014-01-14 20:03:48 +01:00
|
|
|
const u64 new_value = ((u64)value << 32) | 1;
|
|
|
|
|
m_indval = new_value;
|
2013-12-25 18:28:10 +01:00
|
|
|
return true;
|
|
|
|
|
}
|
2013-12-10 23:58:11 +01:00
|
|
|
}
|
2013-11-03 20:23:16 +01:00
|
|
|
}
|
|
|
|
|
|
2013-12-13 02:35:28 +01:00
|
|
|
__forceinline void PushUncond(u32 value)
|
|
|
|
|
{
|
2014-06-02 14:08:32 +02:00
|
|
|
if (max_count > 1)
|
2013-12-25 18:28:10 +01:00
|
|
|
{
|
2014-01-14 20:03:48 +01:00
|
|
|
std::lock_guard<std::mutex> lock(m_lock);
|
2013-12-25 18:28:10 +01:00
|
|
|
if(m_index >= max_count)
|
|
|
|
|
m_value[max_count-1] = value; //last message is overwritten
|
|
|
|
|
else
|
|
|
|
|
m_value[m_index++] = value;
|
|
|
|
|
}
|
2013-12-13 02:35:28 +01:00
|
|
|
else
|
2013-12-25 18:28:10 +01:00
|
|
|
{ //lock-free
|
2014-01-14 20:03:48 +01:00
|
|
|
const u64 new_value = ((u64)value << 32) | 1;
|
|
|
|
|
m_indval = new_value;
|
2013-12-25 18:28:10 +01:00
|
|
|
}
|
2013-12-13 02:35:28 +01:00
|
|
|
}
|
|
|
|
|
|
2013-12-22 18:40:50 +01:00
|
|
|
__forceinline void PushUncond_OR(u32 value)
|
|
|
|
|
{
|
2014-06-02 14:08:32 +02:00
|
|
|
if (max_count > 1)
|
2013-12-25 18:28:10 +01:00
|
|
|
{
|
2014-01-14 20:03:48 +01:00
|
|
|
std::lock_guard<std::mutex> lock(m_lock);
|
2013-12-25 18:28:10 +01:00
|
|
|
if(m_index >= max_count)
|
|
|
|
|
m_value[max_count-1] |= value; //last message is logically ORed
|
|
|
|
|
else
|
|
|
|
|
m_value[m_index++] = value;
|
|
|
|
|
}
|
2013-12-22 18:40:50 +01:00
|
|
|
else
|
2013-12-25 18:28:10 +01:00
|
|
|
{
|
2014-09-23 01:07:40 +02:00
|
|
|
InterlockedOr(&m_indval, ((u64)value << 32) | 1);
|
2013-12-25 18:28:10 +01:00
|
|
|
}
|
2013-12-22 18:40:50 +01:00
|
|
|
}
|
|
|
|
|
|
2013-12-13 02:35:28 +01:00
|
|
|
__forceinline void PopUncond(u32& res)
|
|
|
|
|
{
|
2014-06-02 14:08:32 +02:00
|
|
|
if (max_count > 1)
|
2013-12-25 18:28:10 +01:00
|
|
|
{
|
2014-01-14 20:03:48 +01:00
|
|
|
std::lock_guard<std::mutex> lock(m_lock);
|
2013-12-25 18:28:10 +01:00
|
|
|
if(!m_index)
|
|
|
|
|
res = 0; //result is undefined
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
res = m_value[--m_index];
|
|
|
|
|
m_value[m_index] = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-12-13 02:35:28 +01:00
|
|
|
else
|
2013-12-25 18:28:10 +01:00
|
|
|
{ //lock-free
|
|
|
|
|
if(!m_index)
|
|
|
|
|
res = 0;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
res = (m_indval >> 32);
|
|
|
|
|
m_indval = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-12-13 02:35:28 +01:00
|
|
|
}
|
|
|
|
|
|
2014-01-05 00:58:03 +01:00
|
|
|
__forceinline u32 GetCount()
|
2013-11-03 20:23:16 +01:00
|
|
|
{
|
2014-06-02 14:08:32 +02:00
|
|
|
if (max_count > 1)
|
2013-12-25 18:28:10 +01:00
|
|
|
{
|
2014-01-14 20:03:48 +01:00
|
|
|
std::lock_guard<std::mutex> lock(m_lock);
|
2014-01-05 00:58:03 +01:00
|
|
|
return m_index;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return m_index;
|
2013-12-25 18:28:10 +01:00
|
|
|
}
|
2013-11-03 20:23:16 +01:00
|
|
|
}
|
|
|
|
|
|
2014-01-05 00:58:03 +01:00
|
|
|
__forceinline u32 GetFreeCount()
|
2013-11-03 20:23:16 +01:00
|
|
|
{
|
2014-06-02 14:08:32 +02:00
|
|
|
if (max_count > 1)
|
2013-12-25 18:28:10 +01:00
|
|
|
{
|
2014-01-14 20:03:48 +01:00
|
|
|
std::lock_guard<std::mutex> lock(m_lock);
|
2014-01-05 00:58:03 +01:00
|
|
|
return max_count - m_index;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return max_count - m_index;
|
2013-12-25 18:28:10 +01:00
|
|
|
}
|
2013-11-03 20:23:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SetValue(u32 value)
|
|
|
|
|
{
|
|
|
|
|
m_value[0] = value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u32 GetValue() const
|
|
|
|
|
{
|
|
|
|
|
return m_value[0];
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2013-12-10 23:58:11 +01:00
|
|
|
struct MFCReg
|
2013-11-03 20:23:16 +01:00
|
|
|
{
|
|
|
|
|
Channel<1> LSA;
|
|
|
|
|
Channel<1> EAH;
|
|
|
|
|
Channel<1> EAL;
|
|
|
|
|
Channel<1> Size_Tag;
|
|
|
|
|
Channel<1> CMDStatus;
|
2014-07-16 18:10:18 +02:00
|
|
|
Channel<1> QueryType; // only for prxy
|
2013-11-03 20:23:16 +01:00
|
|
|
Channel<1> QueryMask;
|
|
|
|
|
Channel<1> TagStatus;
|
2014-01-10 02:30:59 +01:00
|
|
|
Channel<1> AtomicStat;
|
2014-07-16 18:10:18 +02:00
|
|
|
} MFC1, MFC2;
|
2013-11-03 20:23:16 +01:00
|
|
|
|
2014-03-15 16:43:14 +01:00
|
|
|
struct StalledList
|
|
|
|
|
{
|
|
|
|
|
u32 lsa;
|
|
|
|
|
u64 ea;
|
|
|
|
|
u16 tag;
|
|
|
|
|
u16 size;
|
|
|
|
|
u32 cmd;
|
|
|
|
|
MFCReg* MFCArgs;
|
|
|
|
|
|
|
|
|
|
StalledList()
|
|
|
|
|
: MFCArgs(nullptr)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
} StallList[32];
|
|
|
|
|
Channel<1> StallStat;
|
|
|
|
|
|
2013-11-03 20:23:16 +01:00
|
|
|
struct
|
|
|
|
|
{
|
|
|
|
|
Channel<1> Out_MBox;
|
2014-06-23 03:03:16 +02:00
|
|
|
Channel<1> Out_IntrMBox;
|
2013-11-03 20:23:16 +01:00
|
|
|
Channel<4> In_MBox;
|
|
|
|
|
Channel<1> Status;
|
|
|
|
|
Channel<1> NPC;
|
2013-12-22 18:40:50 +01:00
|
|
|
Channel<1> SNR[2];
|
2013-11-03 20:23:16 +01:00
|
|
|
} SPU;
|
|
|
|
|
|
2014-08-22 23:15:02 +02:00
|
|
|
void WriteSNR(bool number, u32 value);
|
2014-03-15 21:46:53 +01:00
|
|
|
|
2013-07-06 01:49:38 +02:00
|
|
|
u32 LSA;
|
2012-11-15 00:39:56 +01:00
|
|
|
|
|
|
|
|
union
|
|
|
|
|
{
|
|
|
|
|
u64 EA;
|
|
|
|
|
struct { u32 EAH, EAL; };
|
|
|
|
|
};
|
|
|
|
|
|
2013-11-03 20:23:16 +01:00
|
|
|
DMAC dmac;
|
|
|
|
|
|
2014-08-22 23:15:02 +02:00
|
|
|
void ProcessCmd(u32 cmd, u32 tag, u32 lsa, u64 ea, u32 size);
|
2014-03-15 16:43:14 +01:00
|
|
|
|
2014-08-22 23:15:02 +02:00
|
|
|
void ListCmd(u32 lsa, u64 ea, u16 tag, u16 size, u32 cmd, MFCReg& MFCArgs);
|
2014-03-17 16:07:47 +01:00
|
|
|
|
2014-08-22 23:15:02 +02:00
|
|
|
void EnqMfcCmd(MFCReg& MFCArgs);
|
2014-03-17 16:07:47 +01:00
|
|
|
|
2014-08-22 23:15:02 +02:00
|
|
|
bool CheckEvents();
|
2014-03-17 16:07:47 +01:00
|
|
|
|
2014-08-22 23:15:02 +02:00
|
|
|
u32 GetChannelCount(u32 ch);
|
2014-03-17 16:07:47 +01:00
|
|
|
|
2014-09-06 18:30:13 +02:00
|
|
|
void WriteChannel(u32 ch, const u128& r);
|
2014-03-17 16:07:47 +01:00
|
|
|
|
2014-09-06 18:30:13 +02:00
|
|
|
void ReadChannel(u128& r, u32 ch);
|
2014-03-17 16:07:47 +01:00
|
|
|
|
2014-08-22 23:15:02 +02:00
|
|
|
void StopAndSignal(u32 code);
|
2014-04-06 21:23:32 +02:00
|
|
|
|
2014-09-06 15:33:01 +02:00
|
|
|
u8 ReadLS8 (const u32 lsa) const { return vm::read8 (lsa + m_offset); }
|
|
|
|
|
u16 ReadLS16 (const u32 lsa) const { return vm::read16 (lsa + m_offset); }
|
|
|
|
|
u32 ReadLS32 (const u32 lsa) const { return vm::read32 (lsa + m_offset); }
|
|
|
|
|
u64 ReadLS64 (const u32 lsa) const { return vm::read64 (lsa + m_offset); }
|
|
|
|
|
u128 ReadLS128(const u32 lsa) const { return vm::read128(lsa + m_offset); }
|
|
|
|
|
|
|
|
|
|
void WriteLS8 (const u32 lsa, const u8& data) const { vm::write8 (lsa + m_offset, data); }
|
|
|
|
|
void WriteLS16 (const u32 lsa, const u16& data) const { vm::write16 (lsa + m_offset, data); }
|
|
|
|
|
void WriteLS32 (const u32 lsa, const u32& data) const { vm::write32 (lsa + m_offset, data); }
|
|
|
|
|
void WriteLS64 (const u32 lsa, const u64& data) const { vm::write64 (lsa + m_offset, data); }
|
|
|
|
|
void WriteLS128(const u32 lsa, const u128& data) const { vm::write128(lsa + m_offset, data); }
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2014-09-24 20:44:26 +02:00
|
|
|
std::function<void(SPUThread& CPU)> m_custom_task;
|
|
|
|
|
|
2012-11-15 00:39:56 +01:00
|
|
|
public:
|
2013-11-03 20:23:16 +01:00
|
|
|
SPUThread(CPUThreadType type = CPU_THREAD_SPU);
|
2014-02-02 20:42:32 +01:00
|
|
|
virtual ~SPUThread();
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2014-04-01 02:33:55 +02:00
|
|
|
virtual std::string RegsToString()
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
2014-04-01 02:33:55 +02:00
|
|
|
std::string ret = "Registers:\n=========\n";
|
2013-11-03 20:23:16 +01:00
|
|
|
|
2014-09-06 18:30:13 +02:00
|
|
|
for(uint i=0; i<128; ++i) ret += fmt::Format("GPR[%d] = 0x%s\n", i, GPR[i].to_hex().c_str());
|
2013-11-03 20:23:16 +01:00
|
|
|
|
2012-11-15 00:39:56 +01:00
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-01 02:33:55 +02:00
|
|
|
virtual std::string ReadRegString(const std::string& reg)
|
2013-09-22 13:34:54 +02:00
|
|
|
{
|
2014-04-01 02:33:55 +02:00
|
|
|
std::string::size_type first_brk = reg.find('[');
|
|
|
|
|
if (first_brk != std::string::npos)
|
2013-09-22 13:34:54 +02:00
|
|
|
{
|
|
|
|
|
long reg_index;
|
2014-04-01 02:33:55 +02:00
|
|
|
reg_index = atol(reg.substr(first_brk + 1, reg.length()-2).c_str());
|
|
|
|
|
if (reg.find("GPR")==0) return fmt::Format("%016llx%016llx", GPR[reg_index]._u64[1], GPR[reg_index]._u64[0]);
|
2013-09-22 13:34:54 +02:00
|
|
|
}
|
2014-04-01 02:33:55 +02:00
|
|
|
return "";
|
2013-09-22 13:34:54 +02:00
|
|
|
}
|
|
|
|
|
|
2014-04-01 02:33:55 +02:00
|
|
|
bool WriteRegString(const std::string& reg, std::string value)
|
2013-11-03 20:23:16 +01:00
|
|
|
{
|
2014-04-01 02:33:55 +02:00
|
|
|
while (value.length() < 32) value = "0"+value;
|
|
|
|
|
std::string::size_type first_brk = reg.find('[');
|
|
|
|
|
if (first_brk != std::string::npos)
|
2013-09-22 13:34:54 +02:00
|
|
|
{
|
|
|
|
|
long reg_index;
|
2014-04-01 02:33:55 +02:00
|
|
|
reg_index = atol(reg.substr(first_brk + 1, reg.length() - 2).c_str());
|
|
|
|
|
if (reg.find("GPR")==0)
|
2013-09-22 13:34:54 +02:00
|
|
|
{
|
|
|
|
|
unsigned long long reg_value0;
|
|
|
|
|
unsigned long long reg_value1;
|
2014-04-01 02:33:55 +02:00
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
reg_value0 = std::stoull(value.substr(16, 31), 0, 16);
|
|
|
|
|
reg_value1 = std::stoull(value.substr(0, 15), 0, 16);
|
|
|
|
|
}
|
2014-04-15 16:12:15 +02:00
|
|
|
catch (std::invalid_argument& /*e*/)
|
2014-04-01 02:33:55 +02:00
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2013-09-22 13:34:54 +02:00
|
|
|
GPR[reg_index]._u64[0] = (u64)reg_value0;
|
|
|
|
|
GPR[reg_index]._u64[1] = (u64)reg_value1;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-15 00:39:56 +01:00
|
|
|
public:
|
2013-11-23 19:50:54 +01:00
|
|
|
virtual void InitRegs();
|
2014-07-16 14:09:20 +02:00
|
|
|
virtual void Task();
|
2014-09-24 20:44:26 +02:00
|
|
|
void FastCall(u32 ls_addr);
|
2012-11-15 00:39:56 +01:00
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
virtual void DoReset();
|
|
|
|
|
virtual void DoRun();
|
|
|
|
|
virtual void DoPause();
|
|
|
|
|
virtual void DoResume();
|
|
|
|
|
virtual void DoStop();
|
2014-02-22 01:26:50 +01:00
|
|
|
virtual void DoClose();
|
2013-06-30 10:46:29 +02:00
|
|
|
};
|
|
|
|
|
|
2013-11-19 11:30:58 +01:00
|
|
|
SPUThread& GetCurrentSPUThread();
|