#ifndef __HW_REGISTER_H__
#define __HW_REGISTER_H__

#include "types.h"

struct ro_t {
	static uint32_t	read(volatile uint32_t* reg, uint32_t mask, uint32_t offset) {
		return (*reg >> offset) & mask;
	}
};

struct wo_t {
	static void write (volatile uint32_t* reg, uint32_t mask, uint32_t offset, uint32_t value) {
		*reg = (value & mask) << offset;
	}
};

struct rw_t : ro_t {
	static void write (volatile uint32_t* reg, uint32_t mask, uint32_t offset, uint32_t value) {
		*reg = (*reg & ~(mask << offset)) | ((value & mask) << offset);
	}
};

template <uint32_t address, uint32_t mask, uint32_t offset, class rw_policy>
struct hw_register {
	static void write(uint32_t value) {
		rw_policy::write(reinterpret_cast<volatile uint32_t*>(address), mask, offset, value);
	}
	static uint32_t read(){
		return rw_policy::read(reinterpret_cast<volatile uint32_t*>(address), mask, offset);
	}
	hw_register& operator= (int value) { write(value); return *this; };
	hw_register& operator= (hw_register& rhs) { return write(rhs.read()); };
	operator int() { return read(); };
};

#endif // __HW_REGISTER_H__
