#include <stdint.h>

#define RCC_BASE        0x40021000
#define GPIOA_BASE      0x50000000
#define EXTI_BASE       0x40021800
#define SYSCFG_BASE     0x40010000

// Register offsets
#define RCC_IOPENR      (*(volatile uint32_t *)(RCC_BASE + 0x34)) // I/O port enable
#define RCC_APBENR2     (*(volatile uint32_t *)(RCC_BASE + 0x40)) // SYSCFG enable
#define SYSCFG_ITLINE5  (*(volatile uint32_t *)(SYSCFG_BASE + 0x94)) // EXTI configuration register 1
#define EXTI_IMR1       (*(volatile uint32_t *)(EXTI_BASE + 0x080)) // Interrupt mask register 1
#define EXTI_RTSR1      (*(volatile uint32_t *)(EXTI_BASE + 0x000)) // Rising trigger selection register 1
#define EXTI_FTSR1      (*(volatile uint32_t *)(EXTI_BASE + 0x004)) // Falling trigger selection register 1
#define EXTI_RPR1       (*(volatile uint32_t *)(EXTI_BASE + 0x00C)) // Rising edge Pending register 1
#define EXTI_FPR1       (*(volatile uint32_t *)(EXTI_BASE + 0x010))//Falling edge Pending register 1
#define EXTI_SWIER1     (*(volatile uint32_t *)(EXTI_BASE + 0x008))//Software interrupt enable register1
#define GPIOA_MODER     (*(volatile uint32_t *)(GPIOA_BASE + 0x00)) // GPIO port mode register
#define GPIOA_ODR       (*(volatile uint32_t *)(GPIOA_BASE + 0x14)) // GPIO port output data register
#define NVIC_ISER       (*(volatile uint32_t *)0xE000E100) // Interrupt Set-Enable Register
#define NVIC_PRIOR      (*(volatile uint32_t *)0xE000E400) // Interrupt Set-Enable Register
#define NVIC_IPR_BASE   0xE000E400 // Base address of NVIC_IPR registers
#define NVIC_IPR        ((volatile uint32_t*) NVIC_IPR_BASE)
#define EXTI_EXTICR1    (*(volatile uint32_t *)(EXTI_BASE + 0x060))


// Bit definitions
#define GPIOAEN         (1 << 0)    // GPIOA clock enable
#define SYSCFGEN        (1 << 0)    // SYSCFG clock enable
#define EXTI_LINE_0     (1 << 0)    // EXTI Line 0
#define PA5             (1 << 5)    // GPIO Pin 5

// Function prototypes
void GPIO_Config(void);
void EXTI_Config(void);
void NVIC_Config(void);

void GPIO_Config(void) {
    // Enable GPIOA clock
    RCC_IOPENR |= GPIOAEN;

    // Set PA5 as output (01 in MODER[10:11])
    GPIOA_MODER &= ~(3 << (5 * 2)); // Clear mode bits for PA5
    GPIOA_MODER |= (1 << (5 * 2));  // Set PA5 to output mode

    // PA0 as input (00 in MODER[0:1], default state)
    GPIOA_MODER &= ~(3 << (0 * 2)); // Clear mode bits for PA0
}

void EXTI_Config(void){
  RCC_APBENR2 |= SYSCFGEN;


  EXTI_EXTICR1 &= ~(0xFF);
  EXTI_EXTICR1 |= (0x1<<0);

  EXTI_IMR1  |=  EXTI_LINE_0;

  EXTI->RTSR1 &= ~EXTI_LINE_0;
  EXTI->FTSR1 |=  EXTI_LINE_0;
}

void EXTI0_1_IRQ_handler(void) {
  if (EXTI_FPR1 & EXTI_LINE_0) {
    EXTI_FPR1 |= EXTI_LINE_0;
    GPIOA_ODR |= PA5;
  }
}

int main(void) {

    while (1) {
        // Idle, waiting for interrupt
    }
}



NVIC_SetPriority(EXTI0_1_IRQn, 0x03);
NVIC_EnableIRQ(EXTI0_1_IRQn);