#include <cstdint>
#include <type_traits>
#include <limits>
#include <cstddef>
#include <initializer_list>
#define __IO volatile
typedef struct
{
__IO uint32_t MODER; /*!< GPIO port mode register, Address offset: 0x00 */
__IO uint32_t OTYPER; /*!< GPIO port output type register, Address offset: 0x04 */
__IO uint32_t OSPEEDR; /*!< GPIO port output speed register, Address offset: 0x08 */
__IO uint32_t PUPDR; /*!< GPIO port pull-up/pull-down register, Address offset: 0x0C */
__IO uint32_t IDR; /*!< GPIO port input data register, Address offset: 0x10 */
__IO uint32_t ODR; /*!< GPIO port output data register, Address offset: 0x14 */
__IO uint32_t BSRR; /*!< GPIO port bit set/reset register, Address offset: 0x18 */
__IO uint32_t LCKR; /*!< GPIO port configuration lock register, Address offset: 0x1C */
__IO uint32_t AFR[2]; /*!< GPIO alternate function registers, Address offset: 0x20-0x24 */
} GPIO_TypeDef;
#define PERIPH_BASE 0x40000000U //Peripheral base address in the alias region
#define AHB1PERIPH_BASE (PERIPH_BASE + 0x00020000U)
#define GPIOA_BASE (AHB1PERIPH_BASE + 0x0000U)
#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE)
using std::uint32_t ;
#define __forceinline _Pragma("inline=forced")
constexpr uint32_t OdrShift= 20U ;
constexpr uint32_t IdrShift= 16U ;
constexpr uint32_t PupdrShift = 12U ;
constexpr uint32_t OspeedrShift = 8U ;
constexpr uint32_t OtyperShift = 4U ;
constexpr uint32_t GpioaOdrAddr = GPIOA_BASE + OdrShift ;
constexpr uint32_t GpioaIdrAddr = GPIOA_BASE + IdrShift ;
namespace Case3
{
class Register
{
public:
explicit Register(uint32_t addr) : ptr{ reinterpret_cast<volatile uint32_t *>(addr) } {
}
inline Register &operator^=(const uint32_t right) {
*ptr ^= right;
return *this;
}
private:
volatile std::uint32_t *ptr;
};
}
namespace Case4
{
template<uint32_t addr>
class Register
{
public:
Register() : raw_ptr{reinterpret_cast<volatile uint32_t *>(addr)}
{
}
inline Register &operator^=(const uint32_t right)
{
*raw_ptr ^= right;
return *this;
}
private:
volatile std::uint32_t *raw_ptr;
};
}
namespace Case5
{
template<uint32_t addr>
class Register
{
public:
__forceinline
Register &operator^=(const uint32_t right)
{
*reinterpret_cast<volatile uint32_t *>(addr) ^= right;
return *this;
}
};
}
namespace Case6
{
template<uint32_t addr>
class Register
{
public:
__forceinline
static void Xor(const uint32_t mask)
{
*reinterpret_cast<volatile uint32_t *>(addr) ^= mask;
}
};
}
namespace Case7
{
template<uint32_t addr, uint32_t pinNum>
struct Pin
{ using Registers = GPIO_TypeDef ;
__forceinline inline static void Toggle() {
Registers *GpioPort{reinterpret_cast<Registers*>(addr)};
GpioPort->ODR ^= 1 << pinNum ;
}
};
}
namespace Case8
{
struct WriteReg {};
struct ReadReg {};
struct ReadWriteReg: public WriteReg, public ReadReg {};
template<uint32_t addr, typename T>
class Register
{
public:
__forceinline template <typename T1 = T,
class = typename std::enable_if_t<std::is_base_of<WriteReg, T1>::value>>
Register &operator^=(const uint32_t right)
{
*reinterpret_cast<volatile uint32_t *>(addr) ^= right;
return *this;
}
};
}
namespace Case9
{
struct WriteReg {};
struct ReadReg {};
struct ReadWriteReg: public WriteReg, public ReadReg {};
template<uint32_t addr, typename T>
class Register
{
public:
__forceinline template <typename T1 = T,
class = typename std::enable_if_t<std::is_base_of<WriteReg, T1>::value>>
inline static void Xor(const uint32_t mask)
{
*reinterpret_cast<volatile int*>(addr) ^= mask;
}
};
struct GpioBase {} ;
template<uint32_t addr>
struct Gpio : public GpioBase
{
using Moder = Register<addr, ReadWriteReg>;
using Otyper = Register<addr + OtyperShift, ReadWriteReg> ;
using Ospeedr = Register<addr + OspeedrShift,ReadWriteReg> ;
using Pupdr = Register<addr + PupdrShift,ReadWriteReg> ;
using Idr = Register<addr + IdrShift, ReadReg> ;
using Odr = Register<addr + OdrShift, WriteReg> ;
};
}
namespace Case10
{
template<uint32_t addr, typename T>
class RegisterStructWrapper {
public:
__forceinline template<typename P>
inline static void Xor(P T::*member, int mask) {
reinterpret_cast<T*>(addr)->*member ^= mask ;
}
} ;
}
namespace Case11
{
struct WriteReg {};
struct ReadReg {};
struct ReadWriteReg: public WriteReg, public ReadReg {};
template<uint32_t addr, typename T, volatile uint32_t T::*member, typename RegType>
class Register {
public:
__forceinline template <typename T1 = RegType,
class = typename std::enable_if_t<std::is_base_of<WriteReg, T1>::value>>
inline static void Xor(const uint32_t mask)
{
reinterpret_cast<T*>(addr)->*member ^= mask ;
}
};
template<uint32_t addr, typename T>
struct Gpio
{
using Moder = Register<addr, GPIO_TypeDef, &GPIO_TypeDef::ODR, ReadWriteReg>;
using Otyper = Register<addr, GPIO_TypeDef, &GPIO_TypeDef::OTYPER, ReadWriteReg>;
using Ospeedr = Register<addr, GPIO_TypeDef, &GPIO_TypeDef::OSPEEDR, ReadWriteReg>;
using Pupdr = Register<addr, GPIO_TypeDef, &GPIO_TypeDef::PUPDR, ReadWriteReg>;
using Idr = Register<addr, GPIO_TypeDef, &GPIO_TypeDef::IDR, ReadReg>;
using Odr = Register<addr, GPIO_TypeDef, &GPIO_TypeDef::ODR, WriteReg>;
} ;
} ;
struct Test {
const int a;
const int b;
} ;
template<Test* mystruct>
constexpr int Geta() {
return mystruct->a;
}
Test test{1,2};
int main()
{
// RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN ;
// GPIOA->MODER |= GPIO_MODER_MODE5_0;
Geta<&test>() ;
//Вариант 1
GPIOA->ODR ^= (1 << 5) ;
GPIOA->IDR ^= (1 << 5) ; //глупенько, но можно
//Вариант 2
*reinterpret_cast<volatile uint32_t *>(GpioaOdrAddr) ^= (1 <<5) ;
*reinterpret_cast<volatile uint32_t *>(GpioaIdrAddr) ^= (1 <<5) ;
//Вариант 3
{
using namespace Case3 ;
Register Odr{GpioaOdrAddr};
Odr ^= (1 << 5);
Register Idr{GpioaIdrAddr};
Idr ^= (1 << 5);
}
//Вариант 4
{
using namespace Case4 ;
using GpioaOdr = Register<GpioaOdrAddr>;
GpioaOdr Odr;
Odr ^= (1 << 5);
using GpioaIdr = Register<GpioaIdrAddr>;
GpioaIdr Idr;
Idr ^= (1 << 5);
}
//Вариант 5
{
using namespace Case5 ;
using GpioaOdr = Register<GpioaOdrAddr>;
GpioaOdr Odr;
Odr ^= (1 << 5);
using GpioaIdr = Register<GpioaIdrAddr>;
GpioaIdr Idr;
Idr ^= (1 << 5);
}
//Вариант 6
{
using namespace Case6 ;
using Odr = Register<GpioaOdrAddr>;
Odr::Xor(1 << 5);
using Idr = Register<GpioaIdrAddr>;
Idr::Xor(1 << 5);
}
//Вариант 7
{
using namespace Case7 ;
using Led1 = Pin<GPIOA_BASE,5> ;
Led1::Toggle() ;
//volatile Gpio* GpioA{reinterpret_cast<volatile Gpio*>(GPIOA_BASE)} ;
//GpioA->ODR ^= (1 << 5) ;
//GpioA->IDR ^= (1 << 5) ;
}
//вариант 8
{
using namespace Case8 ;
using GpioaOdr = Register<GpioaOdrAddr, WriteReg> ;
GpioaOdr Odr ;
Odr ^= (1 << 5) ;
using GpioaIdr = Register<GpioaIdrAddr, ReadReg> ;
GpioaIdr Idr ;
//Idr ^= (1 << 5) ; //ошибка, регистра Idr только для чтения
}
//вариант 9
{
using namespace Case9 ;
using Odr = Register<GpioaOdrAddr, WriteReg>;
Odr::Xor(1 << 5);
using Idr = Register<GpioaIdrAddr, ReadReg>;
//Idr::Xor(1 << 5);
using Gpioa = Gpio<GPIOA_BASE> ;
Gpioa::Odr::Xor(1 << 5) ;
//Gpioa::Idr::Xor((1 << 5) ); //ошибка, регистр Idr только для чтения
}
//вариант 10
{
using namespace Case10 ;
using GpioaWarpper = RegisterStructWrapper<GPIOA_BASE, GPIO_TypeDef> ;
GpioaWarpper::Xor(&GPIO_TypeDef::ODR, (1 << 5)) ;
}
//вариант 11
{
using namespace Case11 ;
using GpioaOdr = Register<GPIOA_BASE, GPIO_TypeDef, &GPIO_TypeDef::ODR, WriteReg> ;
using GpioaIdr = Register<GPIOA_BASE, GPIO_TypeDef, &GPIO_TypeDef::IDR, ReadReg> ;
GpioaOdr::Xor(1 << 5) ;
//GpioaIdr::Xor(1 << 5) ;
using Gpioa = Gpio<GPIOA_BASE, GPIO_TypeDef> ;
Gpioa::Odr::Xor(1 << 5) ;
//Gpioa::Idr::Xor((1 << 5) ); //ошибка, регистр Idr только для чтения
}
return 0;
}