#include <stdint.h>

// Macro for register access (volatile pointer dereferencing, not used here)
#define REG32(addr) (*(volatile uint32_t *)(addr))
#define REG16(addr) (*(volatile uint16_t *)(addr))
#define REG8(addr) (*(volatile uint8_t *)(addr))

typedef struct MMIO_device {
    volatile uint16_t hello;
    volatile uint8_t __RESERVED1[2];
    volatile uint16_t status;
    volatile uint8_t __RESERVED2[8];
    volatile uint32_t control;
    // ...and so on
} __attribute__((aligned(4))) MMIO_device;

/* A base address pointing to the start of the 'peripherals' memory region */
#define MEM_PERIPH_BASE 0xDEADBEEF

/* Specific device, often defined as an offset from a base */
#define MY_MMIO (MEM_PERIPH_BASE + 0x10)

#define DVC_CTLR_ENA (0x3 << 1) /* Device Control Register Enable */
#define DVC_CTLR_WRITE (0x1)    /* Device Control Register Write */

volatile MMIO_device *mmio1 = (volatile MMIO_device *)MY_MMIO;

void configure_peripheral() {
    mmio1->hello = 0x1234;                              // Raw write
    mmio1->control |= DVC_CTLR_ENA | DVC_CTLR_WRITE;    // Set
    mmio1->control &= ~(DVC_CTLR_ENA | DVC_CTLR_WRITE); // Clear
}