#ifndef __REGISTER_H__
#define __REGISTER_H__

#include "types.h"

template <typename D>
class Register
{
	public:

		// The register data type.
		typedef D volatile DataType;

		typedef Register Self;

		Register(DataType data = 0 ) : _value(data) {}

	   // Destructor
	   ~Register() {}

		// Read data and return it; same as read().
		operator DataType() const { return _value; }

		// write data and return self; in effect write(data).
		Self& operator= ( DataType data ) { _value = data; return *this; }

		// Test the bit at the given position of the register
		bool BitTest( uint32_t bit ) const { return (_value & BitMask(bit)) ? true : false; }

		uint32_t BitGet ( uint32_t bit ) const { return ((_value & BitMask(bit)) ? 1 : 0); }

		// Clear the bit at the given position of the register
		void BitClear( uint32_t bit ) { _value &= ~BitMask(bit); }

		// set the bit at the given position of the register
		void BitSet( uint32_t bit ) { _value |= BitMask(bit); }

		// Test the bits in the register at the positions given by the mask
		bool MaskTest( DataType mask ) const {return mask == ( _value & mask ); }

		// clear the bits in the register at the positions given by the mask.
		void MaskClear( DataType mask )	{ _value &= ~mask; }

		// set the bits in the register at the positions given by the mask
		void MaskSet( DataType mask )	{ _value |= mask; }

		DataType ExtractBits(uint32_t msBitNum, uint32_t lsBitNum) const {
			return (_value >> lsBitNum) & Mask(msBitNum - lsBitNum + 1);
		}

		void InsertBits(uint32_t msBitNum, uint32_t lsBitNum, DataType data) {
			uint32_t mask = Mask(msBitNum - lsBitNum + 1);
			_value &= ~(mask << lsBitNum);
			_value |= ((data & mask) << lsBitNum);
		}

		// Clear the bits given by clearmask, set the bits given by the setmask
		void MaskSet( DataType clearmask, DataType setmask ) { _value &= ~clearmask; _value |= setmask; }

		// Create bit mask for given bit.
		static DataType BitMask( uint32_t bit ) { return 1 << bit; }

		static DataType Mask(uint32_t size) { return (1 << size) - 1; }

	private:

		// Prevent copy-initialisation.
		Register( Self const& rhs );

		// Prevent copy-assignment.
		Self& operator=( Self const& rhs );

		// Read the register and return its value (reading, ReadOnly access).

		DataType read() const { return _value; }

		// Write the given value to the register
		void write( DataType value) { _value = value; }

		DataType _value;
};

#endif // __REGISTER_H__
