#include "pico/asm_helper.S"
#include "hardware/regs/addressmap.h"
#include "hardware/regs/sio.h"

#if !PICO_RP2040
#warning "Building hardware/divider.S on a platform with no SIO divider hardware"
#endif

pico_default_asm_setup

// tag::hw_div_s32[]
regular_func_with_section hw_divider_divmod_s32
    ldr r3, =(SIO_BASE)
    str r0, [r3, #SIO_DIV_SDIVIDEND_OFFSET]
    str r1, [r3, #SIO_DIV_SDIVISOR_OFFSET]
    b hw_divider_divmod_return
// end::hw_div_s32[]

// tag::hw_div_u32[]
regular_func_with_section hw_divider_divmod_u32
    ldr r3, =(SIO_BASE)
    str r0, [r3, #SIO_DIV_UDIVIDEND_OFFSET]
    str r1, [r3, #SIO_DIV_UDIVISOR_OFFSET]
    b hw_divider_divmod_return
// end::hw_div_u32[]

// Common delay and return section for s32 and u32
.section .text.hw_divider_divmod_return
hw_divider_divmod_return:
    // Branching here is 2 cycles, delay another 6
    b 1f
1:  b 1f
1:  b 1f
1:  // return 64 bit value so we can efficiently return both (note quotient must be read last)
    ldr r1, [r3, #SIO_DIV_REMAINDER_OFFSET]
    ldr r0, [r3, #SIO_DIV_QUOTIENT_OFFSET]
    bx lr

regular_func_with_section hw_divider_save_state
    ldr r3, =SIO_BASE
    ldr r1, [r3, #SIO_DIV_UDIVIDEND_OFFSET]
    ldr r2, [r3, #SIO_DIV_UDIVISOR_OFFSET]
    stmia r0!, {r1-r2}
    // The 8 cycles needed to guarantee that the result is ready is ensured by the preceding
    // code of 7 cycles together with any branch to it taking at least 2 cycles.
    ldr r1, [r3, #SIO_DIV_REMAINDER_OFFSET]
    ldr r2, [r3, #SIO_DIV_QUOTIENT_OFFSET]
    stmia r0!, {r1-r2}
    bx lr

regular_func_with_section hw_divider_restore_state
    ldr r3, =SIO_BASE
    ldmia r0!, {r1-r2}
    str r1, [r3, #SIO_DIV_UDIVIDEND_OFFSET]
    str r2, [r3, #SIO_DIV_UDIVISOR_OFFSET]
    ldmia r0!, {r1-r2}
    str r1, [r3, #SIO_DIV_REMAINDER_OFFSET]
    str r2, [r3, #SIO_DIV_QUOTIENT_OFFSET]
    bx lr
