constexpr auto ByteWidth = CHAR_BIT;

enum class Category
{
    ControlRegister,       //!<  Control Register
    StatusRegister,        //!<  Status Register
    DataRegister,          //!<  Data Register
    TransportRegister,     //!<  Transport Register
};

enum class Permission
{
    Reserved,             //!<  Reserved bit, must be kept at reset value.
    ReadWrite,            //!<  Software can read and write to this bit.
    ReadOnly,             //!<  Software can only read this bit.
    WriteOnly,            //!<  Software can only write to this bit. Reading this bit returns the reset value.
    ReadClearWrite0,      //!<  Software can read as well as clear this bit by writing 0. Writing 1 has no effect on the bit value.
    ReadClearWrite1,      //!<  Software can read as well as clear this bit by writing 1. Writing 0 has no effect on the bit value.
    ReadClearWrite,       //!<  Software can read as well as clear this bit by writing to the register. The value written to this bit is not important.
    ReadClearRead,        //!<  Software can read this bit. Reading this bit automatically clears it to 0. Writing this bit has no effect on the bit value.
    ReadSetRead,          //!<  Software can read this bit. Reading this bit automatically sets it to 1. Writing this bit has no effect on the bit value.
    ReadSet,              //!<  Software can read as well as set this bit. Writing 0 has no effect on the bit value.
    ReadWriteOnce,        //!<  Software can only write once to this bit and can also read it at any time. Only a reset can return the bit to its reset value.
    Toggle,               //!<  The software can toggle this bit by writing 1. Writing 0 has no effect.
    ReadOnlyWriteTrigger, //!<  Software can read this bit. Writing 1 triggers an event but has no effect on the bit value.
};

template <
  typename RegType,
  Category   Category,
  Permission Permission,
  size_t     RightBitPos,
  size_t     Width>
struct VariableFieldBase
{
    RegType m_Reg;
    static_assert(sizeof(RegType) * ByteWidth >= Width + RightBitPos);
    static constexpr RegType Max = (Width < sizeof(RegType) * ByteWidth) ?
                                     ((static_cast<RegType>(1) << (Width)) - 1) :
                                     static_cast<RegType>(~0);

    RegType operator=(const RegType& value) noexcept
    {
        return this->Set(value);
    }

    RegType operator=(const RegType& value) volatile noexcept
    {
        return this->Set(value);
    }

    RegType Set(RegType value) noexcept
    {
        static_assert(
            Permission != Permission::ReadOnly &&
            Permission != Permission::ReadClearRead);
        constexpr RegType Mask = ~(Max << RightBitPos);
        assert(value <= Max);

        if constexpr (Permission == Permission::ReadClearWrite0)
        {
            // TODO: ERROR ハンドリング
            // 0 以外を write しようとした場合は何もしない
            if (value != 0)
            {
                return m_Reg;
            }
        }
        else if constexpr (Permission == Permission::ReadClearWrite1)
        {
            // TODO: ERROR ハンドリング
            // 1 以外を write しようとした場合は何もしない
            if (value != 1)
            {
                return m_Reg;
            }
        }

        if constexpr (Category == Category::ControlRegister || Category == Category::DataRegister)
        {
            // セットするフィールドだけをリセットする
            m_Reg &= Mask;
            m_Reg |= ((Max & value) << RightBitPos);
        }
        else if constexpr (Category == Category::TransportRegister)
        {
            m_Reg = ((Max & value) << RightBitPos);
        }

        return m_Reg;
    }

    RegType Set(RegType value) volatile noexcept
    {
        static_assert(
          Permission != Permission::ReadOnly && Permission != Permission::ReadClearRead);
        constexpr RegType Mask = ~(Max << RightBitPos);
        assert(value <= Max);

        if constexpr (Permission == Permission::ReadClearWrite0)
        {
            if (value != 0)
            {
                return m_Reg;
            }
        }
        else if constexpr (Permission == Permission::ReadClearWrite1)
        {
            if (value != 1)
            {
                return m_Reg;
            }
        }

        if constexpr (Category == Category::ControlRegister || Category == Category::DataRegister)
        {
            // セットするフィールドだけをリセットする
            m_Reg &= Mask;
            m_Reg |= ((Max & value) << RightBitPos);
        }
        else if constexpr (Category == Category::TransportRegister)
        {
            m_Reg = ((Max & value) << RightBitPos);
        }

        return m_Reg;
    }

    RegType Get() const noexcept
    {
        return ((m_Reg >> RightBitPos) & Max);
    }

    RegType Get() volatile const noexcept
    {
        return ((m_Reg >> RightBitPos) & Max);
    }

    operator bool() const noexcept
    {
        return (m_Reg & (Max << RightBitPos)) != 0;
    }

    operator bool() volatile const noexcept
    {
        return (m_Reg & (Max << RightBitPos)) != 0;
    }
};

template <typename RegType, Permission Permission, size_t RightBitPos, size_t Width>
using ControlRegisterFieldBase =
  VariableFieldBase<RegType, Category::ControlRegister, Permission, RightBitPos, Width>;

template <typename RegType, Permission Permission, size_t RightBitPos, size_t Width>
using StatusRegisterFieldBase =
  VariableFieldBase<RegType, Category::StatusRegister, Permission, RightBitPos, Width>;

template <typename RegType, Permission Permission, size_t RightBitPos, size_t Width>
using DataRegisterFieldBase =
  VariableFieldBase<RegType, Category::DataRegister, Permission, RightBitPos, Width>;

template <typename RegType, Permission Permission, size_t RightBitPos, size_t Width>
using TransportRegisterFieldBase =
  VariableFieldBase<RegType, Category::TransportRegister, Permission, RightBitPos, Width>;

template <Permission Permission, size_t RightBitPos, size_t Width>
using ControlRegisterField8 =
  ControlRegisterFieldBase<std::uint8_t, Permission, RightBitPos, Width>;

template <Permission Permission, size_t RightBitPos, size_t Width>
using ControlRegisterField16 =
  ControlRegisterFieldBase<std::uint16_t, Permission, RightBitPos, Width>;

template <Permission Permission, size_t RightBitPos, size_t Width>
using ControlRegisterField32 =
  ControlRegisterFieldBase<std::uint32_t, Permission, RightBitPos, Width>;

template <Permission Permission, size_t RightBitPos, size_t Width>
using ControlRegisterField64 =
  ControlRegisterFieldBase<std::uint64_t, Permission, RightBitPos, Width>;

template <Permission Permission, size_t RightBitPos, size_t Width>
using StatusRegisterField8 = StatusRegisterFieldBase<std::uint8_t, Permission, RightBitPos, Width>;

template <Permission Permission, size_t RightBitPos, size_t Width>
using StatusRegisterField16 =
  StatusRegisterFieldBase<std::uint16_t, Permission, RightBitPos, Width>;

template <Permission Permission, size_t RightBitPos, size_t Width>
using StatusRegisterField32 =
  StatusRegisterFieldBase<std::uint32_t, Permission, RightBitPos, Width>;

template <Permission Permission, size_t RightBitPos, size_t Width>
using StatusRegisterField64 =
  StatusRegisterFieldBase<std::uint64_t, Permission, RightBitPos, Width>;

template <Permission Permission, size_t RightBitPos, size_t Width>
using DataRegisterField8 = DataRegisterFieldBase<std::uint8_t, Permission, RightBitPos, Width>;

template <Permission Permission, size_t RightBitPos, size_t Width>
using DataRegisterField16 = DataRegisterFieldBase<std::uint16_t, Permission, RightBitPos, Width>;

template <Permission Permission, size_t RightBitPos, size_t Width>
using DataRegisterField32 = DataRegisterFieldBase<std::uint32_t, Permission, RightBitPos, Width>;

template <Permission Permission, size_t RightBitPos, size_t Width>
using DataRegisterField64 = DataRegisterFieldBase<std::uint64_t, Permission, RightBitPos, Width>;

template <Permission Permission, size_t RightBitPos, size_t Width>
using TransportRegisterField8 =
  TransportRegisterFieldBase<std::uint8_t, Permission, RightBitPos, Width>;

template <Permission Permission, size_t RightBitPos, size_t Width>
using TransportRegisterField16 =
  TransportRegisterFieldBase<std::uint16_t, Permission, RightBitPos, Width>;

template <Permission Permission, size_t RightBitPos, size_t Width>
using TransportRegisterField32 =
  TransportRegisterFieldBase<std::uint32_t, Permission, RightBitPos, Width>;

template <Permission Permission, size_t RightBitPos, size_t Width>
using TransportRegisterField64 =
  TransportRegisterFieldBase<std::uint64_t, Permission, RightBitPos, Width>;