#****************************************************************************************#
#   Project:    task2 - ASM: Interrupts
#   File:       task2.s
#   Hardware:   STefi Light v1.1
#   Processor:  STM32G431KBT6U
#****************************************************************************************#

    .include "G431_addr.s"

    // Zusätzliche und benötigte Adressen
    .equ RCC_AHB2ENR,    0x4002104C
    .equ RCC_APB2ENR,    0x40021060

    .equ GPIOA_MODER,    0x48000000
    .equ GPIOA_ODR,      0x48000014

    .equ GPIOC_MODER,    0x48000800
    .equ GPIOC_PUPDR,    0x4800080C
    .equ GPIOC_IDR,      0x48000810

    .equ SYSCFG_BASE,    0x40010000
    .equ SYSCFG_EXTICR4, (SYSCFG_BASE + 0x14)

    .equ EXTI_BASE,      0x40010400
    .equ EXTI_IMR1,      (EXTI_BASE + 0x00)
    .equ EXTI_FTSR1,     (EXTI_BASE + 0x0C)
    .equ EXTI_PR1,       (EXTI_BASE + 0x14)

    .equ NVIC_ISER1,     0xE000E104

#----------------------------------------------------------------------------------------#
    .section .vectortable,"a"   // vector table at begin of ROM
#----------------------------------------------------------------------------------------#

    .align  2

    .word   0x20004000          // initial Stack Pointer
    .word   0x08000401          // initial Program Counter
    .word   _ISR_NMI            // non-masking interrupt
    .word   _ISR_HARDF          // hard fault interrupt

    .space  0xD0                // padding 208 Bytes bis Offset 0xE0 (EXTI15_10 IRQ 40)
    .word   _ISR_S0_S1          // gemeinsamer Interrupt für PC13 (S0) und PC14 (S1)

#----------------------------------------------------------------------------------------#
    .text                       // section .text (default section for program code)
#----------------------------------------------------------------------------------------#

    .align  2
    .syntax unified
    .thumb
    .thumb_func
    .global init
    .type   init, %function
init:
    CPSID   i                   // disable interrupts globally

    MOVS    r0, #0              // safely initialize the GPRs
    MOVS    r1, #0
    MOVS    r2, #0
    MOVS    r3, #0
    MOVS    r4, #0
    MOVS    r5, #0
    MOVS    r6, #0
    MOVS    r7, #0
    MOV     r8, r0
    MOV     r9, r0
    MOV     r10, r0
    MOV     r11, r0
    MOV     r12, r0

#--- enable port clocking
    LDR     r1, =RCC_AHB2ENR
    MOVS    r2, #0x05           // Bit 0 (GPIOA) und Bit 2 (GPIOC)
    LDR     r0, [r1, #0]
    ORRS    r0, r2
    STR     r0, [r1, #0]

#--- port init
#- LEDs (PA0-PA3)
    LDR     r1, =GPIOA_MODER
    LDR     r2, =0x000000FF     // Maske PA0-PA3
    LDR     r0, [r1, #0]
    BICS    r0, r2
    LDR     r2, =0x00000055     // Maske Output 0101 0101
    ORRS    r0, r2
    STR     r0, [r1, #0]

#- switch LED off
    LDR     r1, =GPIOA_ODR
    MOVS    r2, #0x0F           // Maske LED0-3
    LDR     r0, [r1, #0]
    ORRS    r0, r2
    STR     r0, [r1, #0]

#- buttons (PC13, PC14 als Input)
    LDR     r1, =GPIOC_MODER
    LDR     r2, =0x3C000000     // Maske Bits 26-29
    LDR     r0, [r1, #0]
    BICS    r0, r2
    STR     r0, [r1, #0]

#- Pull-Up für PC13, PC14
    LDR     r1, =GPIOC_PUPDR
    LDR     r2, =0x3C000000
    LDR     r0, [r1, #0]
    BICS    r0, r2
    LDR     r2, =0x14000000     // 01 = Pull-Up für PC13 (Bits 27:26) und PC14 (Bits 29:28)
    ORRS    r0, r2
    STR     r0, [r1, #0]

#--- button interrupt config

#- enable clock for SYSCFG module
    LDR     r1, =RCC_APB2ENR
    MOVS    r2, #0x01
    LDR     r0, [r1, #0]
    ORRS    r0, r2
    STR     r0, [r1, #0]

#- connect GPIO pins of the buttons to EXTended Interrupt controller lines (EXTI)
    LDR     r1, =SYSCFG_EXTICR4
    LDR     r2, =0x00000FF0     // Maske für EXTI13 (Bits 7:4) und EXTI14 (Bits 11:8)
    LDR     r0, [r1, #0]
    BICS    r0, r2
    LDR     r2, =0x00000220     // Port C (0010) für EXTI13 und EXTI14
    ORRS    r0, r2
    STR     r0, [r1, #0]

#- configure lines in EXTI module (EXTI_* registers)
    LDR     r1, =EXTI_FTSR1     // Fallende Flanke
    LDR     r2, =0x00006000     // Bits 13 und 14
    LDR     r0, [r1, #0]
    ORRS    r0, r2
    STR     r0, [r1, #0]

    LDR     r1, =EXTI_IMR1      // Maskierung aufheben
    LDR     r2, =0x00006000
    LDR     r0, [r1, #0]
    ORRS    r0, r2
    STR     r0, [r1, #0]

#- NVIC: set interrupt priority, clear pending bits
    LDR     r1, =NVIC_ISER1
    LDR     r2, =0x00000100     // Bit 8 für IRQ 40 (EXTI15_10)
    LDR     r0, [r1, #0]
    ORRS    r0, r2
    STR     r0, [r1, #0]

    CPSIE   i                   // enable interrupts globally

#----------------------------------------------------------------------------------------#

    .align  2
    .syntax unified
    .thumb
    .thumb_func
    .global main
    .type   main, %function
main:
    WFI
    B       main

#----------------------------------------------------------------------------------------#

    .align  2
    .syntax unified
    .thumb
    .thumb_func
    .global delay
    .type   delay, %function
delay:
    LDR     r0, =106000         // Entprell-Zeit ~20ms
.L1:
    SUBS    r0, r0, #1
    BNE     .L1
    BX      lr

#----------------------------------------------------------------------------------------#

    .align 2
    .global stop
stop:
    NOP
    B       stop

#----------------------------------------------------------------------------------------#
.lp1:
    .ltorg
#----------------------------------------------------------------------------------------#

#----------------------------------------------------------------------------------------#
    .section .exhand,"ax"       // section for exception handlers
#----------------------------------------------------------------------------------------#

    .align  2
    .syntax unified
    .thumb
    .type   _ISR_NMI, %function
_ISR_NMI:
    LDR     r1, =RCC_AHB2ENR
    MOV     r2, #0x01
    LDR     r0, [r1, #0]
    ORRS    r0, r2
    STR     r0, [r1, #0]

    LDR     r1, =GPIOA_MODER
    MOVS    r2, #0xFF
    LDR     r0, [r1, #0]
    BICS    r0, r2
    MOVS    r2, #0x44
    ORRS    r0, r2
    STR     r0, [r1, #0]

    LDR     r1, =GPIOA_ODR
    MOVS    r2, #0x0A
    LDR     r0, [r1, #0]
    BICS    r0, r2
    STR     r0, [r1, #0]

    B   _ISR_NMI

#----------------------------------------------------------------------------------------#

    .align  2
    .syntax unified
    .thumb
    .type   _ISR_HARDF, %function
_ISR_HARDF:
    LDR     r1, =RCC_AHB2ENR
    MOV     r2, #0x01
    LDR     r0, [r1, #0]
    ORRS    r0, r2
    STR     r0, [r1, #0]

    LDR     r1, =GPIOA_MODER
    MOVS    r2, #0xFF
    LDR     r0, [r1, #0]
    BICS    r0, r2
    MOVS    r2, #0x11
    ORRS    r0, r2
    STR     r0, [r1, #0]

    LDR     r1, =GPIOA_ODR
    MOVS    r2, #0x05
    LDR     r0, [r1, #0]
    BICS    r0, r2
    STR     r0, [r1, #0]

    B       _ISR_HARDF

#----------------------------------------------------------------------------------------#

    .align  2
    .syntax unified
    .thumb
    .type   _ISR_S0_S1, %function
_ISR_S0_S1:
    PUSH    {r4, r5, lr}        // Wichtig: Register sichern gemäß AAPCS

_check_S0:
    LDR     r4, =EXTI_PR1
    LDR     r5, [r4, #0]
    LDR     r2, =0x2000         // Maske für S0 (PC13 / Bit 13)
    TST     r5, r2
    BEQ     _check_S1           // Wenn Bit 13 nicht gesetzt, überspringen

#--- do the work S0
    BL      delay               // Entprellen

    LDR     r0, =GPIOC_IDR
    LDR     r1, [r0, #0]
    LDR     r2, =0x2000
    TST     r1, r2
    BNE     _clear_S0           // Abbruch, wenn High (Taster prellt / schon losgelassen)

    LDR     r0, =GPIOA_ODR
    LDR     r1, [r0, #0]
    MOVS    r2, #0x09           // LED0 & LED3 toggeln (1001)
    EORS    r1, r2
    STR     r1, [r0, #0]

_clear_S0:
#--- clear interrupt flag S0
    LDR     r4, =EXTI_PR1
    LDR     r5, =0x2000
    STR     r5, [r4, #0]

_check_S1:
    LDR     r4, =EXTI_PR1
    LDR     r5, [r4, #0]
    LDR     r2, =0x4000         // Maske für S1 (PC14 / Bit 14)
    TST     r5, r2
    BEQ     _leave_ISR          // Wenn Bit 14 nicht gesetzt, Ende

#--- do the work S1
    BL      delay

    LDR     r0, =GPIOC_IDR
    LDR     r1, [r0, #0]
    LDR     r2, =0x4000
    TST     r1, r2
    BNE     _clear_S1           // Abbruch, wenn High

    LDR     r0, =GPIOA_ODR
    LDR     r1, [r0, #0]
    MOVS    r2, #0x06           // LED1 & LED2 toggeln (0110)
    EORS    r1, r2
    STR     r1, [r0, #0]

_clear_S1:
#--- clear interrupt flag S1
    LDR     r4, =EXTI_PR1
    LDR     r5, =0x4000
    STR     r5, [r4, #0]

_leave_ISR:
#--- leave ISR
    POP     {r4, r5, pc}        // Register wiederherstellen und zurückkehren

#----------------------------------------------------------------------------------------#
.lp2:
    .ltorg
#----------------------------------------------------------------------------------------#

    .end

#************************************** E O F *******************************************#
