#ifndef __JABYENGINE_IOPORT_HPP__ #define __JABYENGINE_IOPORT_HPP__ #include "../../Auxiliary/bits.hpp" struct ClearBitValue { size_t bit; constexpr ClearBitValue(size_t bit) : bit(bit) { } }; template struct Bit { typedef T ValueType; size_t value; constexpr Bit(size_t value) : value(value) { } constexpr operator size_t() const { return this->value; } constexpr ClearBitValue operator!() const { return ClearBitValue(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 struct BitRangeValue { T value; BitRange range; constexpr BitRangeValue(BitRange range, T value) : value(value), range(range) { } }; template static constexpr __always_inline BitRangeValue operator<<(const BitRange& range, T value) { return BitRangeValue(range, value); } 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::clear(this->value, static_cast(bit)); return *this; } template constexpr void clear_bit(S bit) volatile { this->value = bit::clear(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; } // For easier constructing constexpr IOPort& operator|(const BitRangeValue& value) { this->set_value(value.value, value.range); return *this; } constexpr IOPort& operator|(const Bit& bit) { this->set_bit(bit.value); return *this; } constexpr IOPort& operator|(const ClearBitValue& value) { this->clear_bit(value.bit); return *this; } }; 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))) #define __io_port_inherit(name) \ using IOPort::operator=; \ constexpr name() = default; \ constexpr name(IOPort value) : IOPort(value) { \ } #endif //!__JABYENGINE_IOPORT_HPP__