#ifndef __JABYENGINE_IOPORT_HPP__ #define __JABYENGINE_IOPORT_HPP__ #include "../../Auxiliary/bits.hpp" template struct Bit { typedef T ValueType; size_t value; constexpr Bit(size_t value) : value(value) { } constexpr operator size_t() const { return this->value; } }; template struct BitRange { typedef T ValueType; size_t begin; size_t length; static constexpr BitRange from_to(size_t start, size_t end) { return {start, (end - start + 1)}; } }; template class __no_align IOPort { private: T value = 0; public: constexpr IOPort() = default; constexpr IOPort(T value) : value(value) { } //Accesssing bits template constexpr IOPort& set_bit(S bit) { this->value = bit::set(this->value, static_cast(bit)); return *this; } template constexpr void set_bit(S bit) volatile { this->value = bit::set(this->value, static_cast(bit)); } template constexpr IOPort& clear_bit(S bit) { this->value = bit::set(this->value, static_cast(bit)); return *this; } template constexpr void clear_bit(S bit) volatile { this->value = bit::set(this->value, static_cast(bit)); } template constexpr bool is_bit_set(S bit) { return bit::is_set(this->value, static_cast(bit)); } template constexpr bool is_bit_set(S bit) volatile { return bit::is_set(this->value, static_cast(bit)); } //Accessing values template constexpr IOPort& set_value(S value, const BitRange& range) { this->value = bit::value::set_normalized(this->value, static_cast(value), range.begin, range.length); return *this; } template constexpr void set_value(S value, const BitRange& range) volatile { this->value = bit::value::set_normalized(this->value, static_cast(value), range.begin, range.length); } template constexpr IOPort& clear_value(const BitRange& range) { this->value = bit::value::clear_normalized(this->value, range.begin, range.length); return *this; } template constexpr void clear_value(const BitRange& range) volatile { this->value = bit::value::clear_normalized(this->value, range.begin, range.length); } template constexpr S get_value(const BitRange& range) { return static_cast(bit::value::get_normalized(this->value, range.begin, range.length)); } template constexpr S get_value(const BitRange& range) volatile { return static_cast(bit::value::get_normalized(this->value, range.begin, range.length)); } //For easy access constexpr T read() const { return const_cast*>(this)->value; } constexpr void write(T value) { const_cast*>(this)->value = value; } //For raw access constexpr operator T() const { return this->value; } constexpr operator T() const volatile { return this->value; } constexpr IOPort& operator=(T value) { this->value = value; return *this; } constexpr void operator=(T value) volatile { this->value = value; } }; struct __no_align ubus32_t { IOPort low; IOPort high; constexpr ubus32_t(uint32_t value) { *this = value; } constexpr operator uint32_t() const { return ((this->high << 16) | this->low); } constexpr operator uint32_t() const volatile { return ((this->high << 16) | this->low); } constexpr ubus32_t& operator=(uint32_t value) { this->low = (value & 0xFFFF); this->high = (value >> 16); return *this; } constexpr void operator=(uint32_t value) volatile { this->low = (value & 0xFFFF); this->high = (value >> 16); } }; static constexpr uintptr_t IO_Base_Mask = 0xF0000000; static constexpr uintptr_t IO_Base_Adr = 0x10000000; #define __declare_io_port_global(type, name, adr) static __always_inline auto& name = *reinterpret_cast*>((IO_Base_Adr + (adr & ~IO_Base_Mask))) #endif //!__JABYENGINE_IOPORT_HPP__