| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139 |
- /* SPDX-License-Identifier: GPL-2.0-only */
- /*
- * linux/arch/arm/lib/findbit.S
- *
- * Copyright (C) 1995-2000 Russell King
- *
- * 16th March 2001 - John Ripley <jripley@sonicblue.com>
- * Fixed so that "size" is an exclusive not an inclusive quantity.
- * All users of these functions expect exclusive sizes, and may
- * also call with zero size.
- * Reworked by rmk.
- */
- #include <linux/linkage.h>
- #include <asm/assembler.h>
- #include <asm/unwind.h>
- .text
- #ifdef __ARMEB__
- #define SWAB_ENDIAN le
- #else
- #define SWAB_ENDIAN be
- #endif
- .macro find_first, endian, set, name
- ENTRY(_find_first_\name\()bit_\endian)
- UNWIND( .fnstart)
- teq r1, #0
- beq 3f
- mov r2, #0
- 1: ldr r3, [r0], #4
- .ifeq \set
- mvns r3, r3 @ invert/test bits
- .else
- movs r3, r3 @ test bits
- .endif
- .ifc \endian, SWAB_ENDIAN
- bne .L_found_swab
- .else
- bne .L_found @ found the bit?
- .endif
- add r2, r2, #32 @ next index
- 2: cmp r2, r1 @ any more?
- blo 1b
- 3: mov r0, r1 @ no more bits
- ret lr
- UNWIND( .fnend)
- ENDPROC(_find_first_\name\()bit_\endian)
- .endm
- .macro find_next, endian, set, name
- ENTRY(_find_next_\name\()bit_\endian)
- UNWIND( .fnstart)
- cmp r2, r1
- bhs 3b
- mov ip, r2, lsr #5 @ word index
- add r0, r0, ip, lsl #2
- ands ip, r2, #31 @ bit position
- beq 1b
- ldr r3, [r0], #4
- .ifeq \set
- mvn r3, r3 @ invert bits
- .endif
- .ifc \endian, SWAB_ENDIAN
- rev_l r3, ip
- .if .Lrev_l_uses_tmp
- @ we need to recompute ip because rev_l will have overwritten
- @ it.
- and ip, r2, #31 @ bit position
- .endif
- .endif
- movs r3, r3, lsr ip @ shift off unused bits
- bne .L_found
- orr r2, r2, #31 @ no zero bits
- add r2, r2, #1 @ align bit pointer
- b 2b @ loop for next bit
- UNWIND( .fnend)
- ENDPROC(_find_next_\name\()bit_\endian)
- .endm
- .macro find_bit, endian, set, name
- find_first \endian, \set, \name
- find_next \endian, \set, \name
- .endm
- /* _find_first_zero_bit_le and _find_next_zero_bit_le */
- find_bit le, 0, zero_
- /* _find_first_bit_le and _find_next_bit_le */
- find_bit le, 1
- #ifdef __ARMEB__
- /* _find_first_zero_bit_be and _find_next_zero_bit_be */
- find_bit be, 0, zero_
- /* _find_first_bit_be and _find_next_bit_be */
- find_bit be, 1
- #endif
- /*
- * One or more bits in the LSB of r3 are assumed to be set.
- */
- .L_found_swab:
- UNWIND( .fnstart)
- rev_l r3, ip
- .L_found:
- #if __LINUX_ARM_ARCH__ >= 7
- rbit r3, r3 @ reverse bits
- clz r3, r3 @ count high zero bits
- add r0, r2, r3 @ add offset of first set bit
- #elif __LINUX_ARM_ARCH__ >= 5
- rsb r0, r3, #0
- and r3, r3, r0 @ mask out lowest bit set
- clz r3, r3 @ count high zero bits
- rsb r3, r3, #31 @ offset of first set bit
- add r0, r2, r3 @ add offset of first set bit
- #else
- mov ip, #~0
- tst r3, ip, lsr #16 @ test bits 0-15
- addeq r2, r2, #16
- moveq r3, r3, lsr #16
- tst r3, #0x00ff
- addeq r2, r2, #8
- moveq r3, r3, lsr #8
- tst r3, #0x000f
- addeq r2, r2, #4
- moveq r3, r3, lsr #4
- tst r3, #0x0003
- addeq r2, r2, #2
- moveq r3, r3, lsr #2
- tst r3, #0x0001
- addeq r2, r2, #1
- mov r0, r2
- #endif
- cmp r1, r0 @ Clamp to maxbit
- movlo r0, r1
- ret lr
- UNWIND( .fnend)
|