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

  1. //================ Copyright (c) Valve Corporation. All Rights Reserved. ===========================
  2. //
  3. //
  4. //
  5. //==================================================================================================
  6. #ifndef INCLUDED_SPUMGR_SPU_H
  7. #define INCLUDED_SPUMGR_SPU_H
  8. //--------------------------------------------------------------------------------------------------
  9. // Headers
  10. //--------------------------------------------------------------------------------------------------
  11. #include <stdint.h>
  12. #include <string.h>
  13. #include <spu_intrinsics.h>
  14. #include <spu_mfcio.h>
  15. #include <stdlib.h>
  16. #include <cell/atomic.h>
  17. #include "SpuMgr_dma.h"
  18. #include <libsn_spu.h>
  19. //--------------------------------------------------------------------------------------------------
  20. // Defines
  21. //--------------------------------------------------------------------------------------------------
  22. #define DEBUG_ASSERT(val) Assert(val)
  23. #define DEBUG_ERROR(val) Assert(val)
  24. #define Msg(...)
  25. #define Error(...)
  26. #define DebuggerBreak() snPause()
  27. #include <sys/integertypes.h>
  28. //Short aliases
  29. typedef int8_t s8;
  30. typedef uint8_t u8;
  31. typedef int16_t s16;
  32. typedef uint16_t u16;
  33. typedef int32_t s32;
  34. typedef uint32_t u32;
  35. typedef uint32_t u64[2];
  36. typedef float f32;
  37. typedef double f64;
  38. typedef int BOOL;
  39. typedef s8 int8;
  40. typedef u8 uint8;
  41. typedef s16 int16;
  42. typedef u16 uint16;
  43. typedef s32 int32;
  44. typedef u32 uint32;
  45. typedef u64 uint64;
  46. typedef unsigned int uintp;
  47. typedef unsigned int uint;
  48. typedef vector float fltx4 ;
  49. #define INT_MAX 0x7fffffff
  50. #define DECL_ALIGN(x) __attribute__( ( aligned( x ) ) )
  51. #define ALIGN16 DECL_ALIGN(16)
  52. #define ALIGN16_POST
  53. #define ALIGN128 DECL_ALIGN(128)
  54. #define ALIGN128_POST
  55. template <typename T>
  56. inline T AlignValue( T val, uintp alignment )
  57. {
  58. return ( T )( ( ( uintp )val + alignment - 1 ) & ~( alignment - 1 ) );
  59. }
  60. #define ALIGN_VALUE( val, alignment ) ( ( val + alignment - 1 ) & ~( alignment - 1 ) )
  61. inline bool IsPowerOfTwo( uint x )
  62. {
  63. return ( x & ( x - 1 ) ) == 0;
  64. }
  65. #define FORCEINLINE inline /* __attribute__ ((always_inline)) */
  66. #define IsPlatformPS3() 1
  67. #define IsPlatformPS3_PPU() 0
  68. #define IsPlatformPS3_SPU() 1
  69. #define IsPlatformX360() 0
  70. #define IsPlatformOSX() 0
  71. #define RESTRICT
  72. #define V_memset __builtin_memset
  73. #define V_memcpy memcpy
  74. void SPU_memcpy( void *pBuf1, void *pBuf2 );
  75. #define MemAlloc_AllocAligned(size, align) gSpuMgr.MemAlign(align, size)
  76. #define ARRAYSIZE(p) (sizeof(p)/sizeof(p[0]))
  77. #define MIN( a, b ) ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) )
  78. #define MAX( a, b ) ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) )
  79. //--------------------------------------------------------------------------------------------------
  80. // Task handle
  81. //--------------------------------------------------------------------------------------------------
  82. class SpuTaskHandle
  83. {
  84. public:
  85. uint32_t m_spuId;
  86. uint64_t m_ppuThread;
  87. uint32_t m_intrTag;
  88. uint32_t m_interruptThread;
  89. uint32_t m_lock;
  90. uint32_t m_memcpyLock;
  91. };
  92. //--------------------------------------------------------------------------------------------------
  93. // SpuMgr
  94. //--------------------------------------------------------------------------------------------------
  95. class SpuMgr
  96. {
  97. public:
  98. // Init/Term
  99. int Init();
  100. void Term();
  101. // MFC Atomic Update functionality
  102. // Currently provides functionality to read/write up to
  103. // one cache line (128 bytes) of main mem
  104. inline void MFCAGet(void *ls, uint32_t ea, uint32_t size);
  105. inline void MFCAPut(void *ls, uint32_t ea, uint32_t size);
  106. //
  107. // DMA functionality
  108. //
  109. // tagId is a value between 0 and 31 that can be used to group
  110. // dma requests together
  111. void DmaGetSAFE(void *ls, uint32_t ea, uint32_t size, uint32_t tagId);
  112. void DmaGetUNSAFE(void *ls, uint32_t ea, uint32_t size, uint32_t tagId);
  113. void DmaPut(uint32_t ea, void *ls, uint32_t size, uint32_t tagId);
  114. void DmaSmallPut(uint32_t ea, void *ls, uint32_t size, uint32_t tagId);
  115. void DmaGetList(void *ls, DMAList *pLS_List, uint32_t sizeList, uint32_t tagId);
  116. void DmaPutList(void *ls, DMAList* pLS_List, uint32_t sizeList, uint32_t tagId);
  117. inline int DmaDone(uint32_t dmaTagMask, bool bBlocking = true);
  118. // DmaSync
  119. // All earlier store instructions are forced to complete
  120. // before proceeding. This function ensures that all stores to
  121. // to local storage are visible to the MFC or PPU.
  122. inline void DmaSync()
  123. {
  124. __asm("dsync");
  125. }
  126. //
  127. // Mailbox functions - see SpuMgr_ppu.h for a descrition of mailboxes
  128. //
  129. int WriteMailbox(uint32_t val, bool bBlocking = true);
  130. int WriteIntrMailbox(uint32_t val, bool bBlocking = true);
  131. int WriteMailboxChannel(uint32_t val, uint32_t channel, bool bBlocking /* = true */);
  132. int ReadMailbox(uint32_t *pVal, bool bBlocking = true);
  133. bool Lock();
  134. void Unlock();
  135. bool MemcpyLock();
  136. void MemcpyUnlock();
  137. // Decrementer access, for time stamps
  138. inline uint32_t ReadDecr(void);
  139. // mem mgr
  140. void *Malloc( uint32_t size )
  141. {
  142. m_mallocCount++;
  143. void *ptr = malloc( size );
  144. DEBUG_ASSERT( ptr );
  145. return ptr;
  146. }
  147. void *MemAlignUNSAFE(uint32_t boundary, uint32_t size )
  148. {
  149. m_mallocCount++;
  150. void *ptr = memalign( boundary, size );
  151. return ptr;
  152. }
  153. void *MemAlign( uint32_t boundary, uint32_t size )
  154. {
  155. void *ptr = MemAlignUNSAFE(boundary, size);
  156. DEBUG_ERROR( ptr );
  157. return ptr;
  158. }
  159. void Free( void *pData )
  160. {
  161. m_mallocCount--;
  162. free( pData );
  163. }
  164. uint32_t GetMallocCount()
  165. {
  166. return m_mallocCount;
  167. }
  168. // counters to help us keep track of how much data we are moving
  169. inline void ResetBytesTransferred()
  170. {
  171. m_bytesRequested = 0;
  172. m_bytesTransferred = 0;
  173. m_numDMATransfers = 0;
  174. }
  175. // Private data and member functions
  176. void _DmaGet(void *ls, uint32_t ea, uint32_t size, uint32_t tagId);
  177. uint32_t m_lock[32] __attribute__ ((aligned(128)));
  178. uint32_t m_lockEA;
  179. uint32_t m_memcpyLock[32] __attribute__ ((aligned(128)));
  180. uint32_t m_memcpyLockTest;// __attribute__ ((aligned(128)));
  181. uint32_t m_memcpyLockEA;
  182. uint32_t m_bytesRequested;
  183. uint32_t m_bytesTransferred;
  184. uint32_t m_numDMATransfers;
  185. uint32_t m_mallocCount;
  186. uint8_t m_MFCACacheLine[128] __attribute__ ((aligned(128)));
  187. };
  188. //--------------------------------------------------------------------------------------------------
  189. //
  190. //--------------------------------------------------------------------------------------------------
  191. inline void SpuMgr::MFCAGet(void *ls, uint32_t ea, uint32_t size)
  192. {
  193. // get start of cache line
  194. uint32_t eaAligned = SPUMGR_ALIGN_DOWN(ea, 0x80);
  195. // get offset to given ea
  196. uint32_t eaOffset = ea - eaAligned;
  197. // check size to read
  198. DEBUG_ASSERT(size + eaOffset <= 0x80);
  199. // read cache line
  200. spu_mfcdma64(&m_MFCACacheLine[0], 0, eaAligned, 128, 0, MFC_GETLLAR_CMD);
  201. // wait for completion - this is a blocking read
  202. spu_readch(MFC_RdAtomicStat);
  203. // copy out data
  204. memcpy(ls, &m_MFCACacheLine[eaOffset], size);
  205. }
  206. //--------------------------------------------------------------------------------------------------
  207. //
  208. //--------------------------------------------------------------------------------------------------
  209. inline void SpuMgr::MFCAPut(void *ls, uint32_t ea, uint32_t size)
  210. {
  211. // get start of cache line
  212. uint32_t eaAligned = SPUMGR_ALIGN_DOWN(ea, 0x80);
  213. // get offset to given ea
  214. uint32_t eaOffset = ea - eaAligned;
  215. // check size to write
  216. DEBUG_ASSERT(size + eaOffset <= 0x80);
  217. // atmoic update - read cache line and reserve it, update it,
  218. // conditionally write it back until write succeeds
  219. // if write succeeds then spu_readch(MFC_RdAtomicStat) returns 0
  220. do
  221. {
  222. // read cache line
  223. spu_mfcdma64(&m_MFCACacheLine[0], 0, eaAligned, 128, 0, MFC_GETLLAR_CMD);
  224. // wait for completion - this is a blocking read
  225. spu_readch(MFC_RdAtomicStat);
  226. spu_dsync();
  227. // update cache line
  228. memcpy(&m_MFCACacheLine[eaOffset], ls, size);
  229. // dsync to make sure it's commited to LS
  230. spu_dsync();
  231. // write it back
  232. spu_mfcdma64(&m_MFCACacheLine[0], 0, eaAligned, 128, 0, MFC_PUTLLC_CMD);
  233. } while (__builtin_expect(spu_readch(MFC_RdAtomicStat), 0));
  234. }
  235. //--------------------------------------------------------------------------------------------------
  236. //
  237. //--------------------------------------------------------------------------------------------------
  238. inline int SpuMgr::DmaDone(uint32_t dmaTagMask, bool bBlocking /*=true*/)
  239. {
  240. // From Cell Broadband Engine Architecture V1.0 Chapter 9.3.1 "Procedures for Determining the Status of Tag Groups"
  241. //
  242. // For polling for the completion of an MFC command or for the completion of a group of MFC commands, the
  243. // basic procedure is as follows:
  244. // 1. Clear any pending tag status update requests by:
  245. // � Writing a �0� to the MFC Write Tag Status Update Request Channel (see page 116)
  246. // � Reading the channel count associated with the MFC Write Tag Status Update Request Channel (see
  247. // page 116), until a value of �1� is returned
  248. // � Reading the MFC Read Tag-Group Status Channel (see page 117) and discarding the tag status
  249. // data.
  250. // 2. Enable the tag groups of interest by writing the MFC Write Tag-Group Query Mask Channel (see page
  251. // 114) with the appropriate mask data (only needed if a new tag-group mask is required).
  252. // 3. Request an immediate tag status update by writing the MFC Write Tag Status Update Request Channel
  253. // (see page 116) with a value of �0�.
  254. // 4. Perform a read of the MFC Read Tag-Group Status Channel (see page 117). The data returned is the
  255. // current status of each tag group with the tag-group mask applied.
  256. // 5. Repeat steps 3 and 4 until the tag group or the tag groups of interest are complete.
  257. //
  258. // Note
  259. // MFC Write Tag Status Update Request Channel = MFC_WrTagUpdate
  260. // MFC Read Tag-Group Status Channel = MFC_RdTagStat
  261. // MFC Write Tag-Group Query Mask Channel = MFC_WrTagMask
  262. // Here we go...
  263. // 1. Clear any pending tag status update requests
  264. spu_writech(MFC_WrTagUpdate, 0);
  265. do {} while (spu_readchcnt(MFC_WrTagUpdate) == 0);
  266. spu_readch(MFC_RdTagStat);
  267. // 2. Enable the tag groups of interest
  268. spu_writech(MFC_WrTagMask, dmaTagMask);
  269. uint32_t dmaDone = 0;
  270. do
  271. {
  272. // 3. Request an immediate tag status update
  273. spu_writech(MFC_WrTagUpdate, 0);
  274. // 4. Perform a read of the MFC Read Tag-Group Status Channel
  275. uint32_t tagGroupStat = spu_readch(MFC_RdTagStat);
  276. dmaDone = (tagGroupStat == dmaTagMask);
  277. } while (bBlocking && !dmaDone);
  278. return !dmaDone;
  279. }
  280. //--------------------------------------------------------------------------------------------------
  281. //
  282. //--------------------------------------------------------------------------------------------------
  283. inline int SpuMgr::WriteMailbox(uint32_t val, bool bBlocking /* = true */)
  284. {
  285. uint32_t mboxAvailable;
  286. do
  287. {
  288. mboxAvailable = spu_readchcnt(SPU_WrOutMbox);
  289. } while (bBlocking && !mboxAvailable);
  290. if (mboxAvailable)
  291. {
  292. spu_writech(SPU_WrOutMbox, val);
  293. }
  294. return !mboxAvailable;
  295. }
  296. //--------------------------------------------------------------------------------------------------
  297. //
  298. //--------------------------------------------------------------------------------------------------
  299. inline int SpuMgr::WriteIntrMailbox(uint32_t val, bool bBlocking /* = true */)
  300. {
  301. uint32_t mboxAvailable;
  302. do
  303. {
  304. mboxAvailable = spu_readchcnt(SPU_WrOutIntrMbox);
  305. } while (bBlocking && !mboxAvailable);
  306. if (mboxAvailable)
  307. {
  308. spu_writech(SPU_WrOutIntrMbox, val);
  309. }
  310. return !mboxAvailable;
  311. }
  312. //--------------------------------------------------------------------------------------------------
  313. //
  314. //--------------------------------------------------------------------------------------------------
  315. inline int SpuMgr::ReadMailbox(uint32_t *pVal, bool bBlocking /* = true */)
  316. {
  317. uint32_t mailAvailable;
  318. do
  319. {
  320. mailAvailable = spu_readchcnt(SPU_RdInMbox);
  321. } while (bBlocking && !mailAvailable);
  322. if (mailAvailable)
  323. *pVal = spu_readch(SPU_RdInMbox);
  324. return !mailAvailable;
  325. }
  326. //--------------------------------------------------------------------------------------------------
  327. //
  328. //--------------------------------------------------------------------------------------------------
  329. inline uint32_t SpuMgr::ReadDecr(void)
  330. {
  331. return spu_readch(SPU_RdDec);
  332. }
  333. //--------------------------------------------------------------------------------------------------
  334. //
  335. //--------------------------------------------------------------------------------------------------
  336. inline bool SpuMgr::Lock()
  337. {
  338. return cellAtomicCompareAndSwap32( m_lock, m_lockEA, 0, 1 ) == 0;
  339. }
  340. //--------------------------------------------------------------------------------------------------
  341. //
  342. //--------------------------------------------------------------------------------------------------
  343. inline void SpuMgr::Unlock()
  344. {
  345. cellAtomicCompareAndSwap32( m_lock, m_lockEA, 1, 0 );
  346. }
  347. //--------------------------------------------------------------------------------------------------
  348. //
  349. //--------------------------------------------------------------------------------------------------
  350. inline bool SpuMgr::MemcpyLock()
  351. {
  352. return cellAtomicCompareAndSwap32( m_memcpyLock, m_memcpyLockEA, 0, 1 ) == 0;
  353. }
  354. //--------------------------------------------------------------------------------------------------
  355. //
  356. //--------------------------------------------------------------------------------------------------
  357. inline void SpuMgr::MemcpyUnlock()
  358. {
  359. cellAtomicCompareAndSwap32( m_memcpyLock, m_memcpyLockEA, 1, 0 );
  360. }
  361. //--------------------------------------------------------------------------------------------------
  362. // Externs
  363. //--------------------------------------------------------------------------------------------------
  364. extern SpuMgr gSpuMgr;
  365. #endif // INCLUDED_SPUMGR_SPU_H