#if !defined	SPUUTIL_RAWSPU_H_
#define			SPUUTIL_RAWSPU_H_

#include <types.h>

#include <sys/raw_spu.h>


#if defined __cplusplus
extern "C"
{
#endif



//taken form raw_spu.h

const uint64_t RAW_SPU_OFFSET 		= 0x0000000000100000;
const uint64_t RAW_SPU_BASE_ADDR 	= 0x00000000e0000000;
const uint64_t RAW_SPU_LS_OFFSET 	= 0x0000000000000000;
const uint64_t RAW_SPU_PROB_OFFSET 	= 0x0000000000040000;



const uint32_t	INTR_PU_MB_MASK		= (0x1 << 0);
const uint32_t	INTR_STOP_MASK		= (0x1 << 1);
const uint32_t	INTR_HALT_MASK		= (0x1 << 2);
const uint32_t	INTR_DMA_MASK		= (0x1 << 3);
const uint32_t	INTR_SPU_MB_MASK	= (0x1 << 4);


inline void rawspu_WriteProblemStateWord( uint64_t base, uint64_t offset, uint32_t value )
{
	*(reinterpret_cast< volatile uint32_t* >( base + RAW_SPU_PROB_OFFSET + offset )) = value;
}


inline uint32_t rawspu_ReadProblemStateWord( uint64_t base, uint64_t offset )
{
	return *(reinterpret_cast< volatile uint32_t* >( base + RAW_SPU_PROB_OFFSET + offset ));
}



#if defined __cplusplus
}
#endif





#if defined __cplusplus

namespace spuutil
{
	class RawSPU
	{
	public:

		enum PROBLEMSTATEOFFSETTYPE
		{
			//The following values are copied from BPA Book I-II-III p.104

			DMA_CMD				= 0x3014,//[8:15] 						- low 16 at 0x3014
			DMA_ClassID			= 0x3014,//[0:7]TClassID [8:15]RClassID. 	- high 16 at 0x3014

			DMA_Tag				= 0x3010,//[0:10] zero [11:15] tag		- low 16 at 0x3010
			DMA_Size			= 0x3010,//[0] resv [1:15] tran/list size	- high 16 at 0x3010

			DMA_LSA				= 0x3004,//[0:31] lsa
			DMA_EAL				= 0x300c,//[0:31] ea low
			DMA_EAH				= 0x3008,//[0:31] ea high

			DMA_CMDStatus		= 0x3014,//[0:15] impl spec [16:29] resv [30:31] DMA cmd return
			DMA_QStatus			= 0x3104,//[0] queue status [1:15] resv [16:31] queue space avail

			Prxy_QueryType		= 0x3204,//[0:29] resv [30:31] tag status update condition

			Prxy_QueryMask		= 0x321c,
			Prxy_TagStatus		= 0x322c,

			PU_MB				= 0x4004,//[0:31] mail data
			SPU_MB				= 0x400c,//[0:31] mail data
			MB_Stat				= 0x4014,

			SPU_RunCntl			= 0x401c,//[0:29] resv [30:31] run control
			SPU_Status			= 0x4024,
			SPU_NPC				= 0x4034,//[0:30] lsa [31] interrupt enable

			Sig_Notify_1		= 0x1400c,//[0:31] sig word
			Sig_Notify_2		= 0x1c00c,//[0:31] sig word
		};

		enum RAWSPUSTATETYPE
		{
			unallocated	= 0x0,
			ready		= 0x1,
			deployed	= 0x2,
			started		= 0x4,
			unknown		= 0x5,
		};



		RawSPU();

		uint32_t	Release();

		bool		Initialize();
		bool 		Initialize( raw_spu_t spuID );

		bool		SetELF( const char* name );


		bool		Deploy( uint32_t unused );
		bool		Start();
		bool		Stop();
		bool		Reset();

		bool		IsDeployed() const;

		raw_spu_t	SPUID() const;

		bool 		IssueDMACommand( uint32_t command, uint32_t lsAddress, uint8_t* ea, uint32_t size, uint32_t tag );
		bool 		WaitForDMATagGroup( uint32_t tagGroup );
		void		WriteProblemStateWord( PROBLEMSTATEOFFSETTYPE offset, uint32_t value );
		uint32_t	ReadProblemStateWord( PROBLEMSTATEOFFSETTYPE offset );

	private:

		~RawSPU();

		uint32_t	m_refCount;
		raw_spu_t	m_spuID;
		uint64_t	m_baseAddr;
		uint8_t*	m_buffer;
		uint8_t*	m_dmaBuffer;
		uint32_t	m_dmaBufferSize;
		uint32_t	m_dmaTransferSize;
		uint32_t	m_state;
	};
}

#endif


#endif
