/* SCE CONFIDENTIAL
 * PLAYSTATION(R)3 Programmer Tool Runtime Library 084.006
 * Copyright (C) 2006 Sony Computer Entertainment Inc.
 * All Rights Reserved.
 */

/* Buffer::Local - Local(to SPU) Buffer
 */

#ifndef __CELL_DAISY_LOCAL_BUFFER_H__
#define __CELL_DAISY_LOCAL_BUFFER_H__

#ifdef __SPU__
#include <cell/daisy/v_memcpy.h>
#endif
#include <cell/daisy/buffer.h>

#undef CELL_DAISY_DEBUG_PRINTF
#define CELL_DAISY_DEBUG_PRINTF(...)
#ifdef CELL_DAISY_DEBUG_LOCAL_BUFFER
#include <cell/daisy/daisy_debug.h>
#endif

namespace cell {
	namespace Daisy {
		namespace Buffer {
    
			template <typename tType, SizeType tSize
#ifdef __SPU__
					  , ConstructorMode tConstructorMode = NO_PARAMETER
#endif
					  >
			class Local:
				public Abstract<tType, tSize>
			{

			public:
      
				static const BufferType sBufferType = BUFFER_TYPE_LOCAL;			
#ifdef __SPU__
				static const ConstructorMode sConstructorMode = tConstructorMode;			
#endif

			protected:

				volatile tType *mLocalBuffer __CELL_DAISY_SPU_ALIGN16__;

				/* buffer area */
				uint8_t mBuffer[sizeof(tType)*tSize+127] __CELL_DAISY_SPU_ALIGN16__;

			public:
      
				/* data type definition */

				typedef tType DataType;

				virtual const char *getClassName(){
					static char __buf[64];
					cell::Daisy::_snprintf(__buf, 64, "Local[mLocalBuffer=0x%p,tSize:%d, sizeof(tType):%d]",
										   mLocalBuffer,
										   tSize,
										   sizeof(tType));
					return (const char *)__buf;
				}
					
				/* constructor(s) */

				explicit Local();
      
#ifdef __SPU__
				/* Automatic association with shared memory
				 * @param parameterEa paramter exchange buffer Ea
				 * @param spuNum spuNum of myself
				 */
				explicit Local(
					uint64_t parameterEa, /* 128bytes */
					int spuNum
					);
#else /* __SPU__ */

				/*
				 * @param pBuffer pointer to buffer
				 */
				explicit Local(
					volatile void *pBuffer
					);
#endif /* __SPU__ */
				/* member function(s) */
      
				CELL_DAISY_INLINE
					void beginWrite(PointerType ptr, __restrict__ tType *src)
					{
						register PointerType ptr_ = (ptr<(int)tSize)?ptr:ptr-tSize;
						CELL_DAISY_DEBUG_PRINTF(
							"%s(beginWrite): memcpy(&mLocalBuffer[%d]=0x%p, src=0x%p)\n",
							getClassName(), ptr_, &mLocalBuffer[ptr_], src, sizeof(tType));
#ifdef __SPU__
						_cellDaisyMemcpy((void *)(uintptr_t)&mLocalBuffer[ptr_], (const void *)(uintptr_t)src, sizeof(tType));
#else
						__builtin_memcpy((void *)(uintptr_t)&mLocalBuffer[ptr_], (const void *)(uintptr_t)src, sizeof(tType));
#endif
					}
      
				CELL_DAISY_INLINE
					int tryBeginWrite(PointerType ptr, __restrict__ tType *src)
					{
						beginWrite(ptr, src);
						return CELL_OK;
					}
      
				CELL_DAISY_INLINE
					void endWrite(PointerType ptr)
					{ (void)ptr; }
      
				CELL_DAISY_INLINE
					int tryEndWrite(PointerType ptr)
					{
						endWrite(ptr);
						return CELL_OK;
					}
      
				CELL_DAISY_INLINE
					void beginRead(PointerType ptr, __restrict__ tType *dst)
					{
						register PointerType ptr_ = (ptr<(int)tSize)?ptr:ptr-tSize;
						CELL_DAISY_DEBUG_PRINTF(
							"%s(read_begin): memcpy(dst=0x%p, &mLocalBuffer[%d]=0x%p\n",
								getClassName(), dst, ptr_, &mLocalBuffer[ptr_]);
#ifdef __SPU__
						_cellDaisyMemcpy((void *)(uintptr_t)dst, (const void *)(uintptr_t)&mLocalBuffer[ptr_], sizeof(tType));
#else
						__builtin_memcpy((void *)(uintptr_t)dst, (const void *)(uintptr_t)&mLocalBuffer[ptr_], sizeof(tType));
#endif
					}
      
				CELL_DAISY_INLINE
					int tryBeginRead(PointerType ptr, __restrict__ tType *dst)
					{
						beginRead(ptr, dst);
						return CELL_OK;
					}
      
				CELL_DAISY_INLINE
					void endRead(PointerType ptr)
					{ (void)ptr; }
      
				CELL_DAISY_INLINE
					int tryEndRead(PointerType ptr)
					{
						endRead(ptr);
						return CELL_OK;
					}
      
				CELL_DAISY_INLINE
					volatile tType* getEntryReference(PointerType ptr){
					register PointerType ptr_ = (ptr<(int)tSize)?ptr:ptr-tSize;
					CELL_DAISY_DEBUG_PRINTF("%s(getEntryReference): mLocalBuffer[%d]=0x%p\n",
											getClassName(),ptr_, &mLocalBuffer[ptr_]);
					return &mLocalBuffer[ptr_];
				}
      
			}; /* class Buffer::Local */
    
			/* constructor descriptions */

			template <typename tType, SizeType tSize
#ifdef __SPU__
					  , ConstructorMode tConstructorMode
#endif
					  >
			Local<tType, tSize
#ifdef __SPU__
				  , tConstructorMode
#endif
				  >::Local()
			{

				cellDaisyAssert(CELL_DAISY_ENTRY_SIZE(sizeof(tType)));
				cellDaisyAssert(sizeof(tType) >= CELL_DAISY_MIN_ENTRY_SIZE);
				cellDaisyAssert(sizeof(tType) <= CELL_DAISY_MAX_ENTRY_SIZE);
#ifdef __SPU__
				cellDaisyAssert(tConstructorMode == NO_PARAMETER);
#endif

				/* 128 bytes align */
				mLocalBuffer = (tType *)(((uintptr_t)mBuffer + 127) & ~127);
				CELL_DAISY_DEBUG_PRINTF("%s(Constructor):\n", getClassName());
			}
    
#ifdef __SPU__    
			template <typename tType, SizeType tSize, ConstructorMode tConstructorMode>
			Local<tType, tSize, tConstructorMode>::Local(
				uint64_t parameterEa, /* 128bytes */
				int spuNum
				)
			{

				cellDaisyAssert(CELL_DAISY_ENTRY_SIZE(sizeof(tType)));
				cellDaisyAssert(sizeof(tType) >= CELL_DAISY_MIN_ENTRY_SIZE);
				cellDaisyAssert(sizeof(tType) <= CELL_DAISY_MAX_ENTRY_SIZE);
				cellDaisyAssert(tConstructorMode == PARAMETER);
				cellDaisyAssert(CELL_DAISY_EA_ATOMIC((uint32_t)parameterEa));
				cellDaisyAssert(spuNum >= 0);
				cellDaisyAssert(spuNum <= 255);

				/* 128 bytes align */
				mLocalBuffer = (volatile tType *)(((uintptr_t)mBuffer + 127) & ~127);
      
				/* setup shared param buffer */
				uint8_t param0[sizeof(ParameterType)+127];

				ParameterType *param;
				param = (ParameterType *)(((long)param0 + 127) & ~127);

				mfc_getllar((void *)param, parameterEa, 0, 0);
				mfc_read_atomic_status();
				spu_dsync();
				cellDaisyAssert(param->bufferEa == 0);
      
				uint32_t local_buf_lsa = (uint32_t)mLocalBuffer;
      
				param->bufferEa = CELL_DAISY_GET_LS_AREA(spuNum) + (uint64_t)local_buf_lsa;
				CELL_DAISY_DEBUG_PRINTF("%s(Constructor): EA=0x%llx\n",
										getClassName(),
										param->bufferEa);
     
				/* write param data to param shared buffer */
				spu_dsync();
				mfc_putlluc((void *)param, parameterEa, 0, 0);
				mfc_read_atomic_status();

			}

#else /* __SPU__ */

			template <typename tType, SizeType tSize>
			Local<tType, tSize>::Local(
				volatile void *pBuffer
				):
				mLocalBuffer((volatile tType *)pBuffer)
			{
				cellDaisyAssert(CELL_DAISY_ENTRY_SIZE(sizeof(tType)));
				cellDaisyAssert(sizeof(tType) >= CELL_DAISY_MIN_ENTRY_SIZE);
				cellDaisyAssert(sizeof(tType) <= CELL_DAISY_MAX_ENTRY_SIZE);
				cellDaisyAssert(((uintptr_t)pBuffer & 15) == 0);
			}

#endif /* __SPU__ */

		} /* namespace Buffer */
	} /* namespace Daisy */
} /* namespace cell */

#endif /* __CELL_DAISY_LOCAL_BUFFER_H__ */

/*
 * Local Variables:
 * mode:C++
 * tab-width:4
 * End:
 * vim:ts=4:sw=4:
 */
