Counter Strike : Global Offensive Source Code
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.
 
 
 
 
 
 

473 lines
14 KiB

//================ Copyright (c) Valve Corporation. All Rights Reserved. ===========================
//
//
//
//==================================================================================================
#ifndef INCLUDED_SPUMGR_SPU_H
#define INCLUDED_SPUMGR_SPU_H
//--------------------------------------------------------------------------------------------------
// Headers
//--------------------------------------------------------------------------------------------------
#include <stdint.h>
#include <string.h>
#include <spu_intrinsics.h>
#include <spu_mfcio.h>
#include <stdlib.h>
#include <cell/atomic.h>
#include "SpuMgr_dma.h"
#include <libsn_spu.h>
//--------------------------------------------------------------------------------------------------
// Defines
//--------------------------------------------------------------------------------------------------
#define DEBUG_ASSERT(val) Assert(val)
#define DEBUG_ERROR(val) Assert(val)
#define Msg(...)
#define Error(...)
#define DebuggerBreak() snPause()
#include <sys/integertypes.h>
//Short aliases
typedef int8_t s8;
typedef uint8_t u8;
typedef int16_t s16;
typedef uint16_t u16;
typedef int32_t s32;
typedef uint32_t u32;
typedef uint32_t u64[2];
typedef float f32;
typedef double f64;
typedef int BOOL;
typedef s8 int8;
typedef u8 uint8;
typedef s16 int16;
typedef u16 uint16;
typedef s32 int32;
typedef u32 uint32;
typedef u64 uint64;
typedef unsigned int uintp;
typedef unsigned int uint;
typedef vector float fltx4 ;
#define INT_MAX 0x7fffffff
#define DECL_ALIGN(x) __attribute__( ( aligned( x ) ) )
#define ALIGN16 DECL_ALIGN(16)
#define ALIGN16_POST
#define ALIGN128 DECL_ALIGN(128)
#define ALIGN128_POST
template <typename T>
inline T AlignValue( T val, uintp alignment )
{
return ( T )( ( ( uintp )val + alignment - 1 ) & ~( alignment - 1 ) );
}
#define ALIGN_VALUE( val, alignment ) ( ( val + alignment - 1 ) & ~( alignment - 1 ) )
inline bool IsPowerOfTwo( uint x )
{
return ( x & ( x - 1 ) ) == 0;
}
#define FORCEINLINE inline /* __attribute__ ((always_inline)) */
#define IsPlatformPS3() 1
#define IsPlatformPS3_PPU() 0
#define IsPlatformPS3_SPU() 1
#define IsPlatformX360() 0
#define IsPlatformOSX() 0
#define RESTRICT
#define V_memset __builtin_memset
#define V_memcpy memcpy
void SPU_memcpy( void *pBuf1, void *pBuf2 );
#define MemAlloc_AllocAligned(size, align) gSpuMgr.MemAlign(align, size)
#define ARRAYSIZE(p) (sizeof(p)/sizeof(p[0]))
#define MIN( a, b ) ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) )
#define MAX( a, b ) ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) )
//--------------------------------------------------------------------------------------------------
// Task handle
//--------------------------------------------------------------------------------------------------
class SpuTaskHandle
{
public:
uint32_t m_spuId;
uint64_t m_ppuThread;
uint32_t m_intrTag;
uint32_t m_interruptThread;
uint32_t m_lock;
uint32_t m_memcpyLock;
};
//--------------------------------------------------------------------------------------------------
// SpuMgr
//--------------------------------------------------------------------------------------------------
class SpuMgr
{
public:
// Init/Term
int Init();
void Term();
// MFC Atomic Update functionality
// Currently provides functionality to read/write up to
// one cache line (128 bytes) of main mem
inline void MFCAGet(void *ls, uint32_t ea, uint32_t size);
inline void MFCAPut(void *ls, uint32_t ea, uint32_t size);
//
// DMA functionality
//
// tagId is a value between 0 and 31 that can be used to group
// dma requests together
void DmaGetSAFE(void *ls, uint32_t ea, uint32_t size, uint32_t tagId);
void DmaGetUNSAFE(void *ls, uint32_t ea, uint32_t size, uint32_t tagId);
void DmaPut(uint32_t ea, void *ls, uint32_t size, uint32_t tagId);
void DmaSmallPut(uint32_t ea, void *ls, uint32_t size, uint32_t tagId);
void DmaGetList(void *ls, DMAList *pLS_List, uint32_t sizeList, uint32_t tagId);
void DmaPutList(void *ls, DMAList* pLS_List, uint32_t sizeList, uint32_t tagId);
inline int DmaDone(uint32_t dmaTagMask, bool bBlocking = true);
// DmaSync
// All earlier store instructions are forced to complete
// before proceeding. This function ensures that all stores to
// to local storage are visible to the MFC or PPU.
inline void DmaSync()
{
__asm("dsync");
}
//
// Mailbox functions - see SpuMgr_ppu.h for a descrition of mailboxes
//
int WriteMailbox(uint32_t val, bool bBlocking = true);
int WriteIntrMailbox(uint32_t val, bool bBlocking = true);
int WriteMailboxChannel(uint32_t val, uint32_t channel, bool bBlocking /* = true */);
int ReadMailbox(uint32_t *pVal, bool bBlocking = true);
bool Lock();
void Unlock();
bool MemcpyLock();
void MemcpyUnlock();
// Decrementer access, for time stamps
inline uint32_t ReadDecr(void);
// mem mgr
void *Malloc( uint32_t size )
{
m_mallocCount++;
void *ptr = malloc( size );
DEBUG_ASSERT( ptr );
return ptr;
}
void *MemAlignUNSAFE(uint32_t boundary, uint32_t size )
{
m_mallocCount++;
void *ptr = memalign( boundary, size );
return ptr;
}
void *MemAlign( uint32_t boundary, uint32_t size )
{
void *ptr = MemAlignUNSAFE(boundary, size);
DEBUG_ERROR( ptr );
return ptr;
}
void Free( void *pData )
{
m_mallocCount--;
free( pData );
}
uint32_t GetMallocCount()
{
return m_mallocCount;
}
// counters to help us keep track of how much data we are moving
inline void ResetBytesTransferred()
{
m_bytesRequested = 0;
m_bytesTransferred = 0;
m_numDMATransfers = 0;
}
// Private data and member functions
void _DmaGet(void *ls, uint32_t ea, uint32_t size, uint32_t tagId);
uint32_t m_lock[32] __attribute__ ((aligned(128)));
uint32_t m_lockEA;
uint32_t m_memcpyLock[32] __attribute__ ((aligned(128)));
uint32_t m_memcpyLockTest;// __attribute__ ((aligned(128)));
uint32_t m_memcpyLockEA;
uint32_t m_bytesRequested;
uint32_t m_bytesTransferred;
uint32_t m_numDMATransfers;
uint32_t m_mallocCount;
uint8_t m_MFCACacheLine[128] __attribute__ ((aligned(128)));
};
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
inline void SpuMgr::MFCAGet(void *ls, uint32_t ea, uint32_t size)
{
// get start of cache line
uint32_t eaAligned = SPUMGR_ALIGN_DOWN(ea, 0x80);
// get offset to given ea
uint32_t eaOffset = ea - eaAligned;
// check size to read
DEBUG_ASSERT(size + eaOffset <= 0x80);
// read cache line
spu_mfcdma64(&m_MFCACacheLine[0], 0, eaAligned, 128, 0, MFC_GETLLAR_CMD);
// wait for completion - this is a blocking read
spu_readch(MFC_RdAtomicStat);
// copy out data
memcpy(ls, &m_MFCACacheLine[eaOffset], size);
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
inline void SpuMgr::MFCAPut(void *ls, uint32_t ea, uint32_t size)
{
// get start of cache line
uint32_t eaAligned = SPUMGR_ALIGN_DOWN(ea, 0x80);
// get offset to given ea
uint32_t eaOffset = ea - eaAligned;
// check size to write
DEBUG_ASSERT(size + eaOffset <= 0x80);
// atmoic update - read cache line and reserve it, update it,
// conditionally write it back until write succeeds
// if write succeeds then spu_readch(MFC_RdAtomicStat) returns 0
do
{
// read cache line
spu_mfcdma64(&m_MFCACacheLine[0], 0, eaAligned, 128, 0, MFC_GETLLAR_CMD);
// wait for completion - this is a blocking read
spu_readch(MFC_RdAtomicStat);
spu_dsync();
// update cache line
memcpy(&m_MFCACacheLine[eaOffset], ls, size);
// dsync to make sure it's commited to LS
spu_dsync();
// write it back
spu_mfcdma64(&m_MFCACacheLine[0], 0, eaAligned, 128, 0, MFC_PUTLLC_CMD);
} while (__builtin_expect(spu_readch(MFC_RdAtomicStat), 0));
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
inline int SpuMgr::DmaDone(uint32_t dmaTagMask, bool bBlocking /*=true*/)
{
// From Cell Broadband Engine Architecture V1.0 Chapter 9.3.1 "Procedures for Determining the Status of Tag Groups"
//
// For polling for the completion of an MFC command or for the completion of a group of MFC commands, the
// basic procedure is as follows:
// 1. Clear any pending tag status update requests by:
// • Writing a ‘0’ to the MFC Write Tag Status Update Request Channel (see page 116)
// • Reading the channel count associated with the MFC Write Tag Status Update Request Channel (see
// page 116), until a value of ‘1’ is returned
// • Reading the MFC Read Tag-Group Status Channel (see page 117) and discarding the tag status
// data.
// 2. Enable the tag groups of interest by writing the MFC Write Tag-Group Query Mask Channel (see page
// 114) with the appropriate mask data (only needed if a new tag-group mask is required).
// 3. Request an immediate tag status update by writing the MFC Write Tag Status Update Request Channel
// (see page 116) with a value of ‘0’.
// 4. Perform a read of the MFC Read Tag-Group Status Channel (see page 117). The data returned is the
// current status of each tag group with the tag-group mask applied.
// 5. Repeat steps 3 and 4 until the tag group or the tag groups of interest are complete.
//
// Note
// MFC Write Tag Status Update Request Channel = MFC_WrTagUpdate
// MFC Read Tag-Group Status Channel = MFC_RdTagStat
// MFC Write Tag-Group Query Mask Channel = MFC_WrTagMask
// Here we go...
// 1. Clear any pending tag status update requests
spu_writech(MFC_WrTagUpdate, 0);
do {} while (spu_readchcnt(MFC_WrTagUpdate) == 0);
spu_readch(MFC_RdTagStat);
// 2. Enable the tag groups of interest
spu_writech(MFC_WrTagMask, dmaTagMask);
uint32_t dmaDone = 0;
do
{
// 3. Request an immediate tag status update
spu_writech(MFC_WrTagUpdate, 0);
// 4. Perform a read of the MFC Read Tag-Group Status Channel
uint32_t tagGroupStat = spu_readch(MFC_RdTagStat);
dmaDone = (tagGroupStat == dmaTagMask);
} while (bBlocking && !dmaDone);
return !dmaDone;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
inline int SpuMgr::WriteMailbox(uint32_t val, bool bBlocking /* = true */)
{
uint32_t mboxAvailable;
do
{
mboxAvailable = spu_readchcnt(SPU_WrOutMbox);
} while (bBlocking && !mboxAvailable);
if (mboxAvailable)
{
spu_writech(SPU_WrOutMbox, val);
}
return !mboxAvailable;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
inline int SpuMgr::WriteIntrMailbox(uint32_t val, bool bBlocking /* = true */)
{
uint32_t mboxAvailable;
do
{
mboxAvailable = spu_readchcnt(SPU_WrOutIntrMbox);
} while (bBlocking && !mboxAvailable);
if (mboxAvailable)
{
spu_writech(SPU_WrOutIntrMbox, val);
}
return !mboxAvailable;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
inline int SpuMgr::ReadMailbox(uint32_t *pVal, bool bBlocking /* = true */)
{
uint32_t mailAvailable;
do
{
mailAvailable = spu_readchcnt(SPU_RdInMbox);
} while (bBlocking && !mailAvailable);
if (mailAvailable)
*pVal = spu_readch(SPU_RdInMbox);
return !mailAvailable;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
inline uint32_t SpuMgr::ReadDecr(void)
{
return spu_readch(SPU_RdDec);
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
inline bool SpuMgr::Lock()
{
return cellAtomicCompareAndSwap32( m_lock, m_lockEA, 0, 1 ) == 0;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
inline void SpuMgr::Unlock()
{
cellAtomicCompareAndSwap32( m_lock, m_lockEA, 1, 0 );
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
inline bool SpuMgr::MemcpyLock()
{
return cellAtomicCompareAndSwap32( m_memcpyLock, m_memcpyLockEA, 0, 1 ) == 0;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
inline void SpuMgr::MemcpyUnlock()
{
cellAtomicCompareAndSwap32( m_memcpyLock, m_memcpyLockEA, 1, 0 );
}
//--------------------------------------------------------------------------------------------------
// Externs
//--------------------------------------------------------------------------------------------------
extern SpuMgr gSpuMgr;
#endif // INCLUDED_SPUMGR_SPU_H