#include <cstddef>
#include <cstdint>
#include <type_traits>
#include <initializer_list>
#define __forceinline _Pragma("inline=forced")
//#define __forceinline
//Режим доступа к регистрам
struct WriteMode {};
struct ReadMode {};
struct ReadWriteMode: public WriteMode, public ReadMode {};
//Тип регистров в зависимости от размера
template <uint32_t size>
struct RegisterType {} ;
template<>
struct RegisterType<8>
{
using Type = uint8_t ;
} ;
template<>
struct RegisterType<16>
{
using Type = uint16_t ;
} ;
template<>
struct RegisterType<32>
{
using Type = uint32_t ;
} ;
template<>
struct RegisterType<64>
{
using Type = uint64_t ;
} ;
//Базовый класс для работы с регистром
template<uint32_t address, size_t size, typename AccessMode>
struct RegisterBase
{
static constexpr auto Address = address ;
using Type = typename RegisterType<size>::Type ;
//Метод Write будет работать только для регистров, в которые можно записать значение
__forceinline template<typename T = AccessMode,
class = typename std::enable_if_t<std::is_base_of<WriteMode, T>::value>>
inline static void Set(Type value)
{
*reinterpret_cast<Type *>(address) = value ;
}
//Метод Get возвращает целое значение регистра, будет работать только для регистров, которые можно считать
__forceinline template<typename T = AccessMode,
class = typename std::enable_if_t<std::is_base_of<ReadMode, T>::value>>
inline static Type Get()
{
return *reinterpret_cast<Type *>(address) ;
}
} ;
//Базовый класс для работы с битовыми полями регистров
template<typename Reg, size_t offset, size_t size, typename AccessMode>
struct RegisterField
{
using RegType = typename Reg::Type ;
using Register = Reg ;
static constexpr RegType Offset = offset ;
static constexpr RegType Size = size ;
using Access = AccessMode ;
//Метод устанавливает значение битового поля, только в случае, если оно достпуно для записи
__forceinline template<typename T = AccessMode,
class = typename std::enable_if_t<std::is_base_of<WriteMode, T>::value>>
static void Set(RegType value)
{
RegType newRegValue = *reinterpret_cast<RegType *>(Reg::Address) ; //Сохраняем текущее значение регистра
newRegValue &= ~ (((1 << size) - 1) << offset); //Вначале нужно очистить старое значение битового поля
newRegValue |= (value << offset) ; // Затем установить новое
*reinterpret_cast<RegType *>(Reg::Address) = newRegValue ; //И записать новое значение в регистр
}
//Метод устанавливает проверяет установлено ли значение битового поля
__forceinline template<typename T = AccessMode,
class = typename std::enable_if_t<std::is_base_of<ReadMode, T>::value>>
inline static RegType Get()
{
return ((*reinterpret_cast<RegType *>(Reg::Address)) & (((1 << size) - 1) >> offset)) ;
}
};
//Базовый класс для работы с битовыми полями регистров
template<typename Field, typename Base, typename Field::Register::Type value>
struct FieldValueBase
{
using RegType = typename Field::Register::Type ;
//Метод устанавливает значение битового поля, только в случае, если оно достпуно для записи
__forceinline template<typename T = typename Field::Access,
class = typename std::enable_if_t<std::is_base_of<WriteMode, T>::value>>
static void Set()
{
RegType newRegValue = *reinterpret_cast<RegType *>(Field::Register::Address) ; //Сохраняем текущее значение регистра
newRegValue &= ~ (((1 << Field::Size) - 1) << Field::Offset); //Вначале нужно очистить старое значение битового поля
newRegValue |= (value << Field::Offset) ; // Затем установить новое
*reinterpret_cast<RegType *>(Field::Register::Address) = newRegValue ; //И записать новое значение в регистр
}
//Метод устанавливает проверяет установлено ли значение битового поля
__forceinline template<typename T = typename Field::Access,
class = typename std::enable_if_t<std::is_base_of<ReadMode, T>::value>>
inline static bool IsSet()
{
return ((*reinterpret_cast<RegType *>(Field::Register::Address)) &
static_cast<RegType>(((1 << Field::Size) - 1) << Field::Offset)) ==
(value << Field::Offset) ;
}
};
//Класс для работы с битовыми полями. Добавился тип Base, который необходим для того, чтобы проверить, что
//В регистре устанавливаются те битовые поля, которые допустимы для данного регистра
//template<typename Reg, size_t offset, size_t size, typename AccessMode, typename Base, typename Reg::Type value>
template<typename Field, typename Base, typename Field::Register::Type value>
//struct FieldValue: public FieldValueBase<Reg, offset, size, AccessMode, value>
struct FieldValue: public FieldValueBase<Field, Base, value>
{
using Type = typename Field::Register::Type ;
constexpr static auto Mask = static_cast<Type>(1U << Field::Size) - 1U ;
constexpr static auto Value = value ;
constexpr static auto Offset = Field::Offset ;
using BaseType = Base ;
using Access = typename Field::Access ;
} ;
//Класс для работы с регистром, можно передавать список Битовых полей для установки и проверки
template<uint32_t address, size_t size, typename AccessMode, typename FieldValueBaseType, typename ...Args>
class Register
{
public:
using Type = typename RegisterType<size>::Type;
//Метод Set устанавливает битовые поля, только если регистр может использоваться для записи
__forceinline template<typename T = AccessMode,
class = typename std::enable_if_t<std::is_base_of<WriteMode, T>::value>>
static void Set()
{
Type newRegValue = *reinterpret_cast<Type *>(address) ; //Сохраняем текущее значение регистра
newRegValue &= ~GetMask() ; //Сбрасываем битовые поля, которые нужно будет установить
newRegValue |= GetValue() ; //Устанавливаем новые значения битовых полей
*reinterpret_cast<Type *>(address) = newRegValue ; //Записываем в регистра новое значение
}
//Метод IsSet проверяет что все битовые поля из переданного набора установлены
__forceinline template<typename T = AccessMode,
class = typename std::enable_if_t<std::is_base_of<ReadMode, T>::value>>
static bool IsSet()
{
Type newRegValue = *reinterpret_cast<Type *>(address) ;
return ((newRegValue & GetMask()) == GetValue()) ;
}
private:
//Вспомогательный метод, возвращает маску для конктретного битового поля на этапе компиляции.
//Метод определен только в случае, если тип битового поля и базовый тип битового поля для регистра совпадают.
//Т.е. нельзя устанвоить набор битов не соотвествующих набору для для данного регистра.
__forceinline template<typename T,
class = typename std::enable_if_t<std::is_same<FieldValueBaseType, typename T::BaseType>::value>>
static constexpr auto GetIndividualMask()
{
Type result = T::Mask << T::Offset ;
return result ;
}
//Вспомогательный метод, расчитывает общую маску для всего набора битовых полей на этапе компиляции.
static constexpr auto GetMask()
{
const auto values = {GetIndividualMask<Args>()...} ; //распаковываем набор битовых полей через список инициализации
Type result = 0UL;
for (auto const v: values)
{
result |= v ; //для каждого битового поля устанавливаем битовую маску
}
return result ;
}
//Вспомогательный метод, возвращает значение для конктретного битового поля на этапе компиляции.
//Метод определен только в случае, если тип битового поля и базовый тип битового поля для регистра совпадают.
//Т.е. нельзя устанвоить набор битов не соотвествующих набору для для данного регистра.
__forceinline template<typename T,
class = typename std::enable_if_t<std::is_same<FieldValueBaseType, typename T::BaseType>::value>>
static constexpr auto GetIndividualValue()
{
Type result = T::Value << T::Offset ;
return result ;
}
//Вспомогательный метод, расчитывает значение которое нужно установить в регистре для всего набора битовых полей
static constexpr auto GetValue()
{
const auto values = {GetIndividualValue<Args>()...};
Type result = 0UL;
for (const auto v: values)
{
result |= v ;
}
return result ;
}
};
template <typename Reg, size_t offset, size_t size, typename AccessMode, typename BaseType>
struct RCC_AHBENR_GPIOAEN_Values: public RegisterField<Reg, offset, size, AccessMode>
{
using Disable = FieldValue<RCC_AHBENR_GPIOAEN_Values, BaseType, 0U> ;
using Enable = FieldValue<RCC_AHBENR_GPIOAEN_Values, BaseType, 1U> ;
} ;
struct RCC
{
struct RCCAHB1ENRBase {} ;
struct AHB1ENR : public RegisterBase<0x40023830, 32, ReadWriteMode>
{
using GPIOAEN = RCC_AHBENR_GPIOAEN_Values<RCC::AHB1ENR, 0, 1, ReadWriteMode, RCCAHB1ENRBase> ;
} ;
} ;
template <typename Reg, size_t offset, size_t size, typename AccessMode, typename BaseType>
struct GPIOA_IDR_IDR_Values: public RegisterField<Reg, offset, size, AccessMode>
{
using NotSet = FieldValue<GPIOA_IDR_IDR_Values, BaseType, 0U> ;
using Set = FieldValue<GPIOA_IDR_IDR_Values, BaseType, 1U> ;
} ;
template <typename Reg, size_t offset, size_t size, typename AccessMode, typename BaseType>
struct GPIOA_MODER_MODER_Values: public RegisterField<Reg, offset, size, AccessMode>
{
using Input = FieldValue<GPIOA_MODER_MODER_Values, BaseType, 0U> ;
using Output = FieldValue<GPIOA_MODER_MODER_Values, BaseType, 1U> ;
using Alternate = FieldValue<GPIOA_MODER_MODER_Values, BaseType, 2U> ;
using Analog = FieldValue<GPIOA_MODER_MODER_Values, BaseType, 3U> ;
} ;
template <typename Reg, size_t offset, size_t size, typename AccessMode, typename BaseType>
struct GPIOA_BSRR_BR_Values: public RegisterField<Reg, offset, size, AccessMode>
{
using None = FieldValue<GPIOA_BSRR_BR_Values, BaseType, 0U> ;
using Reset = FieldValue<GPIOA_BSRR_BR_Values, BaseType, 1U> ;
} ;
template <typename Reg, size_t offset, size_t size, typename AccessMode, typename BaseType>
struct GPIOA_BSRR_BS_Values: public RegisterField<Reg, offset, size, AccessMode>
{
using None = FieldValue<GPIOA_BSRR_BS_Values, BaseType, 0U> ;
using Set = FieldValue<GPIOA_BSRR_BS_Values, BaseType, 1U> ;
} ;
struct GPIOA
{
struct GPIOAMODERBase {} ;
struct MODER : public RegisterBase<0x40020000, 32, ReadWriteMode>
{
using MODER15 = GPIOA_MODER_MODER_Values<GPIOA::MODER, 30, 2, ReadWriteMode, GPIOAMODERBase> ;
using MODER14 = GPIOA_MODER_MODER_Values<GPIOA::MODER, 28, 2, ReadWriteMode, GPIOAMODERBase> ;
using MODER13 = GPIOA_MODER_MODER_Values<GPIOA::MODER, 26, 2, ReadWriteMode, GPIOAMODERBase> ;
using MODER12 = GPIOA_MODER_MODER_Values<GPIOA::MODER, 24, 2, ReadWriteMode, GPIOAMODERBase> ;
using MODER11 = GPIOA_MODER_MODER_Values<GPIOA::MODER, 22, 2, ReadWriteMode, GPIOAMODERBase> ;
using MODER10 = GPIOA_MODER_MODER_Values<GPIOA::MODER, 20, 2, ReadWriteMode, GPIOAMODERBase> ;
using MODER9 = GPIOA_MODER_MODER_Values<GPIOA::MODER, 18, 2, ReadWriteMode, GPIOAMODERBase> ;
using MODER8 = GPIOA_MODER_MODER_Values<GPIOA::MODER, 16, 2, ReadWriteMode, GPIOAMODERBase> ;
using MODER7 = GPIOA_MODER_MODER_Values<GPIOA::MODER, 14, 2, ReadWriteMode, GPIOAMODERBase> ;
using MODER6 = GPIOA_MODER_MODER_Values<GPIOA::MODER, 12, 2, ReadWriteMode, GPIOAMODERBase> ;
using MODER5 = GPIOA_MODER_MODER_Values<GPIOA::MODER, 10, 2, ReadWriteMode, GPIOAMODERBase> ;
using MODER4 = GPIOA_MODER_MODER_Values<GPIOA::MODER, 8, 2, ReadWriteMode, GPIOAMODERBase> ;
using MODER3 = GPIOA_MODER_MODER_Values<GPIOA::MODER, 6, 2, ReadWriteMode, GPIOAMODERBase> ;
using MODER2 = GPIOA_MODER_MODER_Values<GPIOA::MODER, 4, 2, ReadWriteMode, GPIOAMODERBase> ;
using MODER1 = GPIOA_MODER_MODER_Values<GPIOA::MODER, 2, 2, ReadWriteMode, GPIOAMODERBase> ;
using MODER0 = GPIOA_MODER_MODER_Values<GPIOA::MODER, 0, 2, ReadWriteMode, GPIOAMODERBase> ;
} ;
template<typename... T>
using MODERPack = Register<0x40020000, 32, ReadWriteMode, GPIOAMODERBase, T...> ;
struct GPIOAIDRBase {} ;
struct IDR : public RegisterBase<0x40020010, 32, ReadMode>
{
using IDR15 = GPIOA_IDR_IDR_Values<GPIOA::IDR, 15, 1, ReadMode, GPIOAIDRBase> ;
using IDR14 = GPIOA_IDR_IDR_Values<GPIOA::IDR, 14, 1, ReadMode, GPIOAIDRBase> ;
using IDR13 = GPIOA_IDR_IDR_Values<GPIOA::IDR, 13, 1, ReadMode, GPIOAIDRBase> ;
using IDR12 = GPIOA_IDR_IDR_Values<GPIOA::IDR, 12, 1, ReadMode, GPIOAIDRBase> ;
using IDR11 = GPIOA_IDR_IDR_Values<GPIOA::IDR, 11, 1, ReadMode, GPIOAIDRBase> ;
using IDR10 = GPIOA_IDR_IDR_Values<GPIOA::IDR, 10, 1, ReadMode, GPIOAIDRBase> ;
using IDR9 = GPIOA_IDR_IDR_Values<GPIOA::IDR, 9, 1, ReadMode, GPIOAIDRBase> ;
using IDR8 = GPIOA_IDR_IDR_Values<GPIOA::IDR, 8, 1, ReadMode, GPIOAIDRBase> ;
using IDR7 = GPIOA_IDR_IDR_Values<GPIOA::IDR, 7, 1, ReadMode, GPIOAIDRBase> ;
using IDR6 = GPIOA_IDR_IDR_Values<GPIOA::IDR, 6, 1, ReadMode, GPIOAIDRBase> ;
using IDR5 = GPIOA_IDR_IDR_Values<GPIOA::IDR, 5, 1, ReadMode, GPIOAIDRBase> ;
using IDR4 = GPIOA_IDR_IDR_Values<GPIOA::IDR, 4, 1, ReadMode, GPIOAIDRBase> ;
using IDR3 = GPIOA_IDR_IDR_Values<GPIOA::IDR, 3, 1, ReadMode, GPIOAIDRBase> ;
using IDR2 = GPIOA_IDR_IDR_Values<GPIOA::IDR, 2, 1, ReadMode, GPIOAIDRBase> ;
using IDR1 = GPIOA_IDR_IDR_Values<GPIOA::IDR, 1, 1, ReadMode, GPIOAIDRBase> ;
using IDR0 = GPIOA_IDR_IDR_Values<GPIOA::IDR, 0, 1, ReadMode, GPIOAIDRBase> ;
} ;
template<typename... T>
using IDRPack = Register<0x40020010, 32, ReadMode, GPIOAIDRBase, T...> ;
struct GPIOABSRRBase {} ;
struct BSRR : public RegisterBase<0x40020018, 32, WriteMode>
{
using BR15 = GPIOA_BSRR_BR_Values<GPIOA::BSRR, 31, 1, WriteMode, GPIOABSRRBase> ;
using BR14 = GPIOA_BSRR_BR_Values<GPIOA::BSRR, 30, 1, WriteMode, GPIOABSRRBase> ;
using BR13 = GPIOA_BSRR_BR_Values<GPIOA::BSRR, 29, 1, WriteMode, GPIOABSRRBase> ;
using BR12 = GPIOA_BSRR_BR_Values<GPIOA::BSRR, 28, 1, WriteMode, GPIOABSRRBase> ;
using BR11 = GPIOA_BSRR_BR_Values<GPIOA::BSRR, 27, 1, WriteMode, GPIOABSRRBase> ;
using BR10 = GPIOA_BSRR_BR_Values<GPIOA::BSRR, 26, 1, WriteMode, GPIOABSRRBase> ;
using BR9 = GPIOA_BSRR_BR_Values<GPIOA::BSRR, 25, 1, WriteMode, GPIOABSRRBase> ;
using BR8 = GPIOA_BSRR_BR_Values<GPIOA::BSRR, 24, 1, WriteMode, GPIOABSRRBase> ;
using BR7 = GPIOA_BSRR_BR_Values<GPIOA::BSRR, 23, 1, WriteMode, GPIOABSRRBase> ;
using BR6 = GPIOA_BSRR_BR_Values<GPIOA::BSRR, 22, 1, WriteMode, GPIOABSRRBase> ;
using BR5 = GPIOA_BSRR_BR_Values<GPIOA::BSRR, 21, 1, WriteMode, GPIOABSRRBase> ;
using BR4 = GPIOA_BSRR_BR_Values<GPIOA::BSRR, 20, 1, WriteMode, GPIOABSRRBase> ;
using BR3 = GPIOA_BSRR_BR_Values<GPIOA::BSRR, 19, 1, WriteMode, GPIOABSRRBase> ;
using BR2 = GPIOA_BSRR_BR_Values<GPIOA::BSRR, 18, 1, WriteMode, GPIOABSRRBase> ;
using BR1 = GPIOA_BSRR_BR_Values<GPIOA::BSRR, 17, 1, WriteMode, GPIOABSRRBase> ;
using BR0 = GPIOA_BSRR_BR_Values<GPIOA::BSRR, 16, 1, WriteMode, GPIOABSRRBase> ;
using BS15 = GPIOA_BSRR_BS_Values<GPIOA::BSRR, 15, 1, WriteMode, GPIOABSRRBase> ;
using BS14 = GPIOA_BSRR_BS_Values<GPIOA::BSRR, 14, 1, WriteMode, GPIOABSRRBase> ;
using BS13 = GPIOA_BSRR_BS_Values<GPIOA::BSRR, 13, 1, WriteMode, GPIOABSRRBase> ;
using BS12 = GPIOA_BSRR_BS_Values<GPIOA::BSRR, 12, 1, WriteMode, GPIOABSRRBase> ;
using BS11 = GPIOA_BSRR_BS_Values<GPIOA::BSRR, 11, 1, WriteMode, GPIOABSRRBase> ;
using BS10 = GPIOA_BSRR_BS_Values<GPIOA::BSRR, 10, 1, WriteMode, GPIOABSRRBase> ;
using BS9 = GPIOA_BSRR_BS_Values<GPIOA::BSRR, 9, 1, WriteMode, GPIOABSRRBase> ;
using BS8 = GPIOA_BSRR_BS_Values<GPIOA::BSRR, 8, 1, WriteMode, GPIOABSRRBase> ;
using BS7 = GPIOA_BSRR_BS_Values<GPIOA::BSRR, 7, 1, WriteMode, GPIOABSRRBase> ;
using BS6 = GPIOA_BSRR_BS_Values<GPIOA::BSRR, 6, 1, WriteMode, GPIOABSRRBase> ;
using BS5 = GPIOA_BSRR_BS_Values<GPIOA::BSRR, 5, 1, WriteMode, GPIOABSRRBase> ;
using BS4 = GPIOA_BSRR_BS_Values<GPIOA::BSRR, 4, 1, WriteMode, GPIOABSRRBase> ;
using BS3 = GPIOA_BSRR_BS_Values<GPIOA::BSRR, 3, 1, WriteMode, GPIOABSRRBase> ;
using BS2 = GPIOA_BSRR_BS_Values<GPIOA::BSRR, 2, 1, WriteMode, GPIOABSRRBase> ;
using BS1 = GPIOA_BSRR_BS_Values<GPIOA::BSRR, 1, 1, WriteMode, GPIOABSRRBase> ;
using BS0 = GPIOA_BSRR_BS_Values<GPIOA::BSRR, 0, 1, WriteMode, GPIOABSRRBase> ;
} ;
template<typename... T>
using BSRRPack = Register<0x40020018, 32, WriteMode, GPIOABSRRBase, T...> ;
} ;
int main()
{
RCC::AHB1ENR::GPIOAEN::Enable::Set() ;
RCC::AHB1ENR::GPIOAEN::Enable::Set() ;
GPIOA::MODER::MODER15::Output::Set() ;
GPIOA::MODERPack<
GPIOA::MODER::MODER12::Output,
GPIOA::MODER::MODER14::Analog
>::Set() ;
//*******************************************
// Включаем тактирование на порту GPIOA
//Ошибка компиляции, у регистра APB1ENR нет поля GPIOAEN
//RCC::APB1ENR::GPIOAEN::Enable::Set() ;
//Все хорошо, подали тактирование на порт GPIOA
RCC::AHB1ENR::GPIOAEN::Enable::Set() ;
//Ошибка компиляции, RCC::APB2ENR::TIM1EN::Enable не
//является полем регистра APB1ENR
//RCC::APB1ENRPack<RCC::APB1ENR::TIM2EN::Enable,
// RCC::APB2ENR::TIM1EN::Enable>::Set();
//Ошибка компиляции, регистр BSRR только для записи
//auto result = GPIOA::BSRR::Get() ;
//Ошибка компиляции, значение Reset только для записи
// if (GPIOA::BSRR::BS1::Reset::IsSet())
{
//do something
}
//Ошибка компиляции, значение поля регистра только для чтения
// GPIOA::IDR::IDR5::On::Set()
GPIOA::MODER::MODER15::Output::Set() ;
auto result = GPIOA::MODER::MODER15::Output::IsSet() ;
GPIOA::MODER::Set(2U) ;
auto test = GPIOA::MODER::Get() ;
GPIOA::MODERPack<
GPIOA::MODER::MODER15::Output,
GPIOA::MODER::MODER14::Analog
>::Set() ;
result = GPIOA::MODERPack<
GPIOA::MODER::MODER15::Output,
GPIOA::MODER::MODER14::Analog
>::IsSet() ; ;
GPIOA::MODER::MODER15::Set(2U) ;
test = GPIOA::MODER::MODER15::Get() ;
auto i = GPIOA::IDR::Get() ;
GPIOA::BSRRPack<GPIOA::BSRR::BR0::Reset,
GPIOA::BSRR::BR4::Reset
>::Set() ;
return 0 ;
}