//================ Copyright (c) Valve Corporation. All Rights Reserved. =========================== // // Raw SPU management // //================================================================================================== #ifndef INCLUDED_SPUMGR_PPU_H #define INCLUDED_SPUMGR_PPU_H //-------------------------------------------------------------------------------------------------- // Headers //-------------------------------------------------------------------------------------------------- #include #include #include #include #include #include #include #include //-------------------------------------------------------------------------------------------------- // //-------------------------------------------------------------------------------------------------- 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