1/* 2 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 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" 10 11#if SIO_DIV_CSR_READY_LSB == 0 12.equ SIO_DIV_CSR_READY_SHIFT_FOR_CARRY, 1 13#else 14need 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 19need to change SHIFT above 20#endif 21 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 27// 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 33 34// 6 cycle push + 2 ldr ensures the 8 cycle delay before remainder and quotient are ready 35push {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! 37ldr r4, [r2, #SIO_DIV_UDIVIDEND_OFFSET] 38ldr r5, [r2, #SIO_DIV_UDIVISOR_OFFSET] 39ldr r7, [r2, #SIO_DIV_REMAINDER_OFFSET] 40ldr r6, [r2, #SIO_DIV_QUOTIENT_OFFSET] 41.endm 42 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 46// 47// it is worth considering what happens if we are interrupted 48// 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 58 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 63str r4, [r2, #SIO_DIV_UDIVIDEND_OFFSET] 64str r5, [r2, #SIO_DIV_UDIVISOR_OFFSET] 65str r7, [r2, #SIO_DIV_REMAINDER_OFFSET] 66str r6, [r2, #SIO_DIV_QUOTIENT_OFFSET] 67pop {r4, r5, r6, r7, pc} 68.endm