; ARM assembly tutorial for Asmonite, example 11 for the Raspberry Pi Pico (RP2040, Arm Cortex-M0+).
; Adapted from the ARM-ASM-Tutorial by Niklas Guertler (examples BlinkFunctionCallingConvention 1 to 3);
; see ..\LICENSE.txt.
;
; The same program as ..\11_calling_convention.asm; the calling convention is the same on the M0+. What
; is different: "push" and "pop" take only r0 .. r7 and lr (push) or pc (pop); "mov r4, r0" works with
; all registers, but "movs" with a number only with r0 .. r7 (0 .. 255).
.target pico
.arch thumb
.imagebase 0x20000000

RESETS_BASE         equ 0x4000c000
RESETS_RESET_DONE   equ 0x08
RESET_BITS          equ (1 << 5) | (1 << 8)     ; IO_BANK0, PADS_BANK0
IO_BANK0_BASE       equ 0x40014000
GPIO25_CTRL         equ 0xcc
FUNCSEL_SIO         equ 5
SIO_BASE            equ 0xd0000000
SIO_GPIO_OUT_SET    equ 0x14
SIO_GPIO_OUT_CLR    equ 0x18
SIO_GPIO_OE_SET     equ 0x24
ALIAS_CLR           equ 0x3000
DELAY_COUNT         equ 1000000

_start:
    bl   setup_led
    movs r0, #5
    bl   blink
    b    $

; ---- blink(r0 = number of flashes) ----
blink:
    push {r4, r5, r6, lr}
    mov  r4, r0
    ldr  r5, lit_sio
    ldr  r6, lit_led_bit
blink_loop:
    str  r6, [r5, #SIO_GPIO_OUT_SET]
    ldr  r0, lit_delay_value
    bl   delay
    str  r6, [r5, #SIO_GPIO_OUT_CLR]
    ldr  r0, lit_delay_value
    bl   delay
    subs r4, r4, #1
    bne  blink_loop
    pop  {r4, r5, r6, pc}

; ---- delay(r0 = iterations) ----
delay:
    subs r0, r0, #1
    bne  delay
    bx   lr

; ---- IO_BANK0 and PADS_BANK0 out of reset, GPIO 25: SIO, output; changes r0 .. r2 ----
setup_led:
    ldr  r1, lit_resets_clr
    ldr  r0, lit_reset_bits
    str  r0, [r1]
    ldr  r1, lit_resets
setup_wait:
    ldr  r2, [r1, #RESETS_RESET_DONE]
    ands r2, r0
    cmp  r2, r0
    bne  setup_wait
    ldr  r1, lit_gpio25_ctrl      ; the M0+: an offset of at most 124 in str, so the whole address
    movs r0, #FUNCSEL_SIO
    str  r0, [r1]
    ldr  r1, lit_sio
    ldr  r0, lit_led_bit
    str  r0, [r1, #SIO_GPIO_OE_SET]
    bx   lr

    align 4
lit_resets:      dd RESETS_BASE
lit_resets_clr:  dd RESETS_BASE + ALIAS_CLR
lit_reset_bits:  dd RESET_BITS
lit_gpio25_ctrl: dd IO_BANK0_BASE + GPIO25_CTRL
lit_sio:         dd SIO_BASE
lit_led_bit:     dd 1 << 25
lit_delay_value: dd DELAY_COUNT
