You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
238 lines
8.9 KiB
238 lines
8.9 KiB
//================ Copyright (c) Valve Corporation. All Rights Reserved. ===========================
|
|
//
|
|
// Raw SPU management
|
|
//
|
|
//==================================================================================================
|
|
|
|
#ifndef INCLUDED_SPUMGR_PPU_H
|
|
#define INCLUDED_SPUMGR_PPU_H
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
// Headers
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
#include <sys/spu_initialize.h>
|
|
#include <sys/raw_spu.h>
|
|
#include <sys/spu_utility.h>
|
|
#include <sys/ppu_thread.h>
|
|
#include <sys/interrupt.h>
|
|
#include <sys/raw_spu.h>
|
|
#include <sys/sys_time.h>
|
|
|
|
#include <cell/spurs.h>
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
extern "C"
|
|
{
|
|
extern void (*g_snRawSPULockHandler) (void);
|
|
extern void (*g_snRawSPUUnlockHandler) (void);
|
|
extern void (*g_snRawSPUNotifyCreation) (unsigned int uID);
|
|
extern void (*g_snRawSPUNotifyDestruction) (unsigned int uID);
|
|
extern void (*g_snRawSPUNotifyElfLoad) (unsigned int uID, unsigned int uEntry, const char *pFileName);
|
|
extern void (*g_snRawSPUNotifyElfLoadNoWait) (unsigned int uID, unsigned int uEntry, const char *pFileName);
|
|
extern void (*g_snRawSPUNotifyElfLoadAbs) (unsigned int uID, unsigned int uEntry, const char *pFileName);
|
|
extern void (*g_snRawSPUNotifyElfLoadAbsNoWait) (unsigned int uID, unsigned int uEntry, const char *pFileName);
|
|
extern void (*g_snRawSPUNotifySPUStopped) (unsigned int uID);
|
|
extern void (*g_snRawSPUNotifySPUStarted) (unsigned int uID);
|
|
};
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
// Fwd refs
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
class CellSpurs2;
|
|
class SpuTaskHandle;
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
// Defines
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
#define MAX_RAW_SPUS 5
|
|
|
|
// Class 2 Interrupt Status Register (INT_Stat_class2)
|
|
// Described in CBE architecture v10 on page 259
|
|
#define INTR_PPU_MB_SHIFT 0
|
|
#define INTR_STOP_SHIFT 1
|
|
#define INTR_HALT_SHIFT 2
|
|
#define INTR_DMA_SHIFT 3
|
|
#define INTR_SPU_MB_SHIFT 4
|
|
#define INTR_PPU_MB_MASK (0x1 << INTR_PPU_MB_SHIFT)
|
|
#define INTR_STOP_MASK (0x1 << INTR_STOP_SHIFT)
|
|
#define INTR_HALT_MASK (0x1 << INTR_HALT_SHIFT)
|
|
#define INTR_DMA_MASK (0x1 << INTR_DMA_SHIFT)
|
|
#define INTR_SPU_MB_MASK (0x1 << INTR_SPU_MB_SHIFT)
|
|
|
|
// thread priority for interrupt handler threads
|
|
#define INTR_HANDLER_THREAD_PRIORITY 200
|
|
#define INTR_HANDLER_THREAD_STACK_SIZE 0x4000
|
|
|
|
#define SPUMGR_IS_ALIGNED(val, align) (((val) & ((align) - 1)) == 0)
|
|
#define SPUMGR_ALIGN_UP(val, align) (((val) + ((align)-1)) & ~((align) - 1))
|
|
#define SPUMGR_ALIGN_DOWN(val, align) ((val) & ~((align) - 1))
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
// Overide sys_raw_spu_mmio_read / write, since they draw out another bug in SNC :(
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
#define sys_raw_spu_mmio_read(spu, regoffset) spumgr_mmio_read(spu, regoffset)
|
|
extern uint32_t spumgr_mmio_read(uint32_t spu, uint32_t regoffset);
|
|
|
|
#define sys_raw_spu_mmio_write(spu, regoffset, value) spumgr_mmio_write(spu, regoffset, value)
|
|
extern void spumgr_mmio_write(int id, int offset, uint32_t value);
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
// Types
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
typedef int CreateSPUTaskCallback(SpuTaskHandle *pTask);
|
|
|
|
// SpuStatusRegister
|
|
// Described in CBE architecture v10 on page 87
|
|
typedef union SpuStatusRegister
|
|
{
|
|
struct
|
|
{
|
|
uint32_t m_sc : 16;
|
|
uint32_t m_reserved2 : 5;
|
|
uint32_t m_isolateExitStatus : 1;
|
|
uint32_t m_isolateLoadStatus : 1;
|
|
uint32_t m_reserved1 : 1;
|
|
uint32_t m_isolationStatus : 1;
|
|
uint32_t m_illegalChannelInstructionDetected : 1;
|
|
uint32_t m_invalidInstructionDetected : 1;
|
|
uint32_t m_singleStepStatus : 1;
|
|
uint32_t m_waitStatus : 1;
|
|
uint32_t m_haltStatus : 1;
|
|
uint32_t m_programStopAndSignalStatus : 1;
|
|
uint32_t m_runStatus : 1;
|
|
};
|
|
uint32_t m_val;
|
|
} SpuStatusRegister;
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
// Classes
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
class SpuTaskHandle
|
|
{
|
|
public:
|
|
sys_raw_spu_t m_spuId;
|
|
sys_ppu_thread_t m_ppuThread;
|
|
sys_interrupt_tag_t m_intrTag;
|
|
sys_interrupt_thread_handle_t m_interruptThread;
|
|
uint32_t m_lock;
|
|
uint32_t m_memcpyLock;
|
|
};
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
// SpuMgr
|
|
//
|
|
// Provides functionality for running raw spu tasks. For this purpose it creates
|
|
// and manages a raw spu pool
|
|
//
|
|
// Currently we assume a simple setup where app loads an elf on to a raw spu,
|
|
// after which the spu starts running the elf and continues to do so thereafter.
|
|
// The ppu->spu and spu->ppu communication is explicitly handled by the app
|
|
// and the spu program using SpuMgr methods
|
|
//
|
|
// Currently all DMA transfer is supposed to be initiated by the SPUs which is
|
|
// why SpuMgr does not provide any DMA functionality
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
class SpuMgr
|
|
{
|
|
public:
|
|
|
|
// Init/Term
|
|
|
|
int Init(int numRawSpu);
|
|
void Term();
|
|
|
|
// Create/Destroy tasks
|
|
|
|
int CreateSpuTask(const char *path, SpuTaskHandle *pTask, CreateSPUTaskCallback *pfnCallback = NULL);
|
|
void DestroySpuTask(SpuTaskHandle *pTask);
|
|
|
|
//
|
|
// Helper functions to communicate with the SPU
|
|
// As we build more functionality into the SPU mgr it is
|
|
// possible that we will need to expose less of
|
|
// these low-level functions
|
|
//
|
|
|
|
//
|
|
// Mailbox functions
|
|
//
|
|
|
|
//
|
|
// The SPU Inbound Mailbox is a 4-level FIFO structure for communication from the
|
|
// PPU to SPU, and can hold up to four 32-bit messages.
|
|
// If there are already four messages in the mailbox the last message will be
|
|
// overwritten...but we can check for a full mailbox and prevent this
|
|
int WriteMailbox(SpuTaskHandle *pTask, uint32_t val, bool bBlocking = true);
|
|
|
|
// The SPU Outbound Mailbox can hold one 32-bit message for SPU-to-PPU communication.
|
|
int ReadMailbox(SpuTaskHandle *pTask, uint32_t *pVal, bool bBlocking = true);
|
|
|
|
// The SPU Outbound Interrupt Mailbox can hold one 32-bit message for SPU-to-PPU communication.
|
|
int ReadIntrMailbox(SpuTaskHandle *pTask, uint32_t *pVal, bool bBlocking = true);
|
|
//
|
|
// Access to local store - note that this involves MMIO which will be slow
|
|
// so need to use DMA instead for any significant data transfer. This
|
|
// mechanism may be useful for writing some small amount of data such
|
|
// as some constants etc into LS
|
|
//
|
|
|
|
int WriteLS(SpuTaskHandle *pTask, uint32_t lsOffset, void *pData, uint32_t size);
|
|
int ReadLS(SpuTaskHandle *pTask, uint32_t lsOffset, void *pData, uint32_t size);
|
|
|
|
bool Lock( SpuTaskHandle *pTask );
|
|
void Unlock( SpuTaskHandle *pTask );
|
|
|
|
bool MemcpyLock( SpuTaskHandle *pTask );
|
|
void MemcpyUnlock( SpuTaskHandle *pTask );
|
|
|
|
|
|
// CellSpurs2 m_exclusiveSpusSpurs; // SPURS instance running on SPUs used exclusively by the application
|
|
// CellSpurs2 m_preemptedSpuSpurs; // SPURS instance running on an SPU shared with the OS (may be preempted by it occasionally)
|
|
|
|
private:
|
|
|
|
uint32_t m_numSpus;
|
|
uint32_t m_spuInUse[MAX_RAW_SPUS];
|
|
sys_raw_spu_t m_spuIds[MAX_RAW_SPUS];
|
|
|
|
int ReadMailboxChannel(SpuTaskHandle *pTask, uint32_t *pVal,
|
|
uint32_t countMask, uint32_t channel, bool bBlocking = true);
|
|
};
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
// Externs
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
extern SpuMgr gSpuMgr;
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
// DmaCheckAlignment
|
|
// Checks restrictions specified in SpuMgr::DmaGet
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
int DmaCheckAlignment(uint32_t src, uint32_t dest, uint32_t size);
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
// GetStopSignal
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
inline uint32_t GetStopSignal( sys_raw_spu_t idSpu )
|
|
{
|
|
SpuStatusRegister status;
|
|
status.m_val = sys_raw_spu_mmio_read(idSpu, SPU_Status);
|
|
uint32_t stopSignal = status.m_sc;
|
|
return stopSignal;
|
|
}
|
|
|
|
#endif // INCLUDED_SPUMGR_PPU_H
|