Adding RP2350 SDK and target framework (#13988)
[betaflight.git] / lib / main / pico-sdk / rp2_common / hardware_divider / include / hardware / divider_helper.S
blobff4ed919bdbe8e8703c5cf727599b1b1d26a6c99
1 /*
2  * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
7 // Note this file is always included by another, so does not do pico_default_asm_setup
8 #include "hardware/regs/addressmap.h"
9 #include "hardware/regs/sio.h"
11 #if SIO_DIV_CSR_READY_LSB == 0
12 .equ SIO_DIV_CSR_READY_SHIFT_FOR_CARRY, 1
13 #else
14 need to change SHIFT above
15 #endif
16 #if SIO_DIV_CSR_DIRTY_LSB == 1
17 .equ SIO_DIV_CSR_DIRTY_SHIFT_FOR_CARRY, 2
18 #else
19 need to change SHIFT above
20 #endif
22 // SIO_BASE ptr in r2; pushes r4-r7, lr to stack
23 .macro save_div_state_and_lr
24 // originally we did this, however a) it uses r3, and b) the push and dividend/divisor
25 // readout takes 8 cycles, c) any IRQ which uses the divider will necessarily put the
26 // data back, which will immediately make it ready
28 //    // ldr r3, [r2, #SIO_DIV_CSR_OFFSET]
29 //    // // wait for results as we can't save signed-ness of operation
30 //    // 1:
31 //    //     lsrs r3, #SIO_DIV_CSR_READY_SHIFT_FOR_CARRY
32 //    //     bcc 1b
34 // 6 cycle push + 2 ldr ensures the 8 cycle delay before remainder and quotient are ready
35 push {r4, r5, r6, r7, lr}
36 // note we must read quotient last, and since it isn't the last reg, we'll not use ldmia!
37 ldr r4, [r2, #SIO_DIV_UDIVIDEND_OFFSET]
38 ldr r5, [r2, #SIO_DIV_UDIVISOR_OFFSET]
39 ldr r7, [r2, #SIO_DIV_REMAINDER_OFFSET]
40 ldr r6, [r2, #SIO_DIV_QUOTIENT_OFFSET]
41 .endm
43 // restores divider state from r4-r7, then pops them and pc
44 .macro restore_div_state_and_return
45 // writing sdividend (r4), sdivisor (r5), quotient (r6), remainder (r7) in that order
47 // it is worth considering what happens if we are interrupted
49 // after writing r4: we are DIRTY and !READY
50 //    ... interruptor using div will complete based on incorrect inputs, but dividend at least will be
51 //        saved/restored correctly and we'll restore the rest ourselves
52 // after writing r4, r5: we are DIRTY and !READY
53 //    ... interruptor using div will complete based on possibly wrongly signed inputs, but dividend, divisor
54 //        at least will be saved/restored correctly and and we'll restore the rest ourselves
55 // after writing r4, r5, r6: we are DIRTY and READY
56 //    ... interruptor using div will dividend, divisor, quotient registers as is (what we just restored ourselves),
57 //        and we'll restore the remainder after the fact
59 // note we are not use STM not because it can be restarted due to interrupt which is harmless, more because this is 1 cycle IO space
60 //      and so 4 reads is cheaper (and we don't have to adjust r2)
61 // note also, that we must restore via UDIVI* rather than SDIVI* to prevent the quotient/remainder being negated on read based
62 //      on the signs of the inputs
63 str r4, [r2, #SIO_DIV_UDIVIDEND_OFFSET]
64 str r5, [r2, #SIO_DIV_UDIVISOR_OFFSET]
65 str r7, [r2, #SIO_DIV_REMAINDER_OFFSET]
66 str r6, [r2, #SIO_DIV_QUOTIENT_OFFSET]
67 pop {r4, r5, r6, r7, pc}
68 .endm