Commit 96cf5185a95e0b304596fe19edcf8dfcd5c10699

Authored by GuanXuetao
1 parent 77c93b2f23

unicore32 additional architecture files: low-level lib: misc

This patch implements the rest low-level libraries.

Signed-off-by: Guan Xuetao <gxt@mprc.pku.edu.cn>
Acked-by: Arnd Bergmann <arnd@arndb.de>

Showing 10 changed files with 662 additions and 0 deletions Side-by-side Diff

arch/unicore32/include/asm/assembler.h
  1 +/*
  2 + * linux/arch/unicore32/include/asm/assembler.h
  3 + *
  4 + * Code specific to PKUnity SoC and UniCore ISA
  5 + *
  6 + * Copyright (C) 2001-2010 GUAN Xue-tao
  7 + *
  8 + * This program is free software; you can redistribute it and/or modify
  9 + * it under the terms of the GNU General Public License version 2 as
  10 + * published by the Free Software Foundation.
  11 + *
  12 + * Do not include any C declarations in this file - it is included by
  13 + * assembler source.
  14 + */
  15 +#ifndef __ASSEMBLY__
  16 +#error "Only include this from assembly code"
  17 +#endif
  18 +
  19 +#include <asm/ptrace.h>
  20 +
  21 +/*
  22 + * Little Endian independent macros for shifting bytes within registers.
  23 + */
  24 +#define pull >>
  25 +#define push <<
  26 +#define get_byte_0 << #0
  27 +#define get_byte_1 >> #8
  28 +#define get_byte_2 >> #16
  29 +#define get_byte_3 >> #24
  30 +#define put_byte_0 << #0
  31 +#define put_byte_1 << #8
  32 +#define put_byte_2 << #16
  33 +#define put_byte_3 << #24
  34 +
  35 +#define cadd cmpadd
  36 +#define cand cmpand
  37 +#define csub cmpsub
  38 +#define cxor cmpxor
  39 +
  40 +/*
  41 + * Enable and disable interrupts
  42 + */
  43 + .macro disable_irq, temp
  44 + mov \temp, asr
  45 + andn \temp, \temp, #0xFF
  46 + or \temp, \temp, #PSR_I_BIT | PRIV_MODE
  47 + mov.a asr, \temp
  48 + .endm
  49 +
  50 + .macro enable_irq, temp
  51 + mov \temp, asr
  52 + andn \temp, \temp, #0xFF
  53 + or \temp, \temp, #PRIV_MODE
  54 + mov.a asr, \temp
  55 + .endm
  56 +
  57 +#define USER(x...) \
  58 +9999: x; \
  59 + .pushsection __ex_table, "a"; \
  60 + .align 3; \
  61 + .long 9999b, 9001f; \
  62 + .popsection
  63 +
  64 + .macro notcond, cond, nexti = .+8
  65 + .ifc \cond, eq
  66 + bne \nexti
  67 + .else; .ifc \cond, ne
  68 + beq \nexti
  69 + .else; .ifc \cond, ea
  70 + bub \nexti
  71 + .else; .ifc \cond, ub
  72 + bea \nexti
  73 + .else; .ifc \cond, fs
  74 + bns \nexti
  75 + .else; .ifc \cond, ns
  76 + bfs \nexti
  77 + .else; .ifc \cond, fv
  78 + bnv \nexti
  79 + .else; .ifc \cond, nv
  80 + bfv \nexti
  81 + .else; .ifc \cond, ua
  82 + beb \nexti
  83 + .else; .ifc \cond, eb
  84 + bua \nexti
  85 + .else; .ifc \cond, eg
  86 + bsl \nexti
  87 + .else; .ifc \cond, sl
  88 + beg \nexti
  89 + .else; .ifc \cond, sg
  90 + bel \nexti
  91 + .else; .ifc \cond, el
  92 + bsg \nexti
  93 + .else; .ifnc \cond, al
  94 + .error "Unknown cond in notcond macro argument"
  95 + .endif; .endif; .endif; .endif; .endif; .endif; .endif
  96 + .endif; .endif; .endif; .endif; .endif; .endif; .endif
  97 + .endif
  98 + .endm
  99 +
  100 + .macro usracc, instr, reg, ptr, inc, cond, rept, abort
  101 + .rept \rept
  102 + notcond \cond, .+8
  103 +9999 :
  104 + .if \inc == 1
  105 + \instr\()b.u \reg, [\ptr], #\inc
  106 + .elseif \inc == 4
  107 + \instr\()w.u \reg, [\ptr], #\inc
  108 + .else
  109 + .error "Unsupported inc macro argument"
  110 + .endif
  111 +
  112 + .pushsection __ex_table, "a"
  113 + .align 3
  114 + .long 9999b, \abort
  115 + .popsection
  116 + .endr
  117 + .endm
  118 +
  119 + .macro strusr, reg, ptr, inc, cond = al, rept = 1, abort = 9001f
  120 + usracc st, \reg, \ptr, \inc, \cond, \rept, \abort
  121 + .endm
  122 +
  123 + .macro ldrusr, reg, ptr, inc, cond = al, rept = 1, abort = 9001f
  124 + usracc ld, \reg, \ptr, \inc, \cond, \rept, \abort
  125 + .endm
  126 +
  127 + .macro nop8
  128 + .rept 8
  129 + nop
  130 + .endr
  131 + .endm
arch/unicore32/include/asm/bitops.h
  1 +/*
  2 + * linux/arch/unicore32/include/asm/bitops.h
  3 + *
  4 + * Code specific to PKUnity SoC and UniCore ISA
  5 + *
  6 + * Copyright (C) 2001-2010 GUAN Xue-tao
  7 + *
  8 + * This program is free software; you can redistribute it and/or modify
  9 + * it under the terms of the GNU General Public License version 2 as
  10 + * published by the Free Software Foundation.
  11 + */
  12 +
  13 +#ifndef __UNICORE_BITOPS_H__
  14 +#define __UNICORE_BITOPS_H__
  15 +
  16 +#define find_next_bit __uc32_find_next_bit
  17 +#define find_next_zero_bit __uc32_find_next_zero_bit
  18 +
  19 +#define find_first_bit __uc32_find_first_bit
  20 +#define find_first_zero_bit __uc32_find_first_zero_bit
  21 +
  22 +#define _ASM_GENERIC_BITOPS_FLS_H_
  23 +#define _ASM_GENERIC_BITOPS___FLS_H_
  24 +#define _ASM_GENERIC_BITOPS_FFS_H_
  25 +#define _ASM_GENERIC_BITOPS___FFS_H_
  26 +/*
  27 + * On UNICORE, those functions can be implemented around
  28 + * the cntlz instruction for much better code efficiency.
  29 + */
  30 +
  31 +static inline int fls(int x)
  32 +{
  33 + int ret;
  34 +
  35 + asm("cntlz\t%0, %1" : "=r" (ret) : "r" (x) : "cc");
  36 + ret = 32 - ret;
  37 +
  38 + return ret;
  39 +}
  40 +
  41 +#define __fls(x) (fls(x) - 1)
  42 +#define ffs(x) ({ unsigned long __t = (x); fls(__t & -__t); })
  43 +#define __ffs(x) (ffs(x) - 1)
  44 +
  45 +#include <asm-generic/bitops.h>
  46 +
  47 +#endif /* __UNICORE_BITOPS_H__ */
arch/unicore32/include/asm/checksum.h
  1 +/*
  2 + * linux/arch/unicore32/include/asm/checksum.h
  3 + *
  4 + * Code specific to PKUnity SoC and UniCore ISA
  5 + *
  6 + * Copyright (C) 2001-2010 GUAN Xue-tao
  7 + *
  8 + * This program is free software; you can redistribute it and/or modify
  9 + * it under the terms of the GNU General Public License version 2 as
  10 + * published by the Free Software Foundation.
  11 + *
  12 + * IP checksum routines
  13 + */
  14 +#ifndef __UNICORE_CHECKSUM_H__
  15 +#define __UNICORE_CHECKSUM_H__
  16 +
  17 +/*
  18 + * computes the checksum of the TCP/UDP pseudo-header
  19 + * returns a 16-bit checksum, already complemented
  20 + */
  21 +
  22 +static inline __wsum
  23 +csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len,
  24 + unsigned short proto, __wsum sum)
  25 +{
  26 + __asm__(
  27 + "add.a %0, %1, %2\n"
  28 + "addc.a %0, %0, %3\n"
  29 + "addc.a %0, %0, %4 << #8\n"
  30 + "addc.a %0, %0, %5\n"
  31 + "addc %0, %0, #0\n"
  32 + : "=&r"(sum)
  33 + : "r" (sum), "r" (daddr), "r" (saddr), "r" (len), "Ir" (htons(proto))
  34 + : "cc");
  35 + return sum;
  36 +}
  37 +#define csum_tcpudp_nofold csum_tcpudp_nofold
  38 +
  39 +#include <asm-generic/checksum.h>
  40 +
  41 +#endif
arch/unicore32/include/asm/delay.h
  1 +/*
  2 + * linux/arch/unicore32/include/asm/delay.h
  3 + *
  4 + * Code specific to PKUnity SoC and UniCore ISA
  5 + *
  6 + * Copyright (C) 2001-2010 GUAN Xue-tao
  7 + *
  8 + * This program is free software; you can redistribute it and/or modify
  9 + * it under the terms of the GNU General Public License version 2 as
  10 + * published by the Free Software Foundation.
  11 + *
  12 + * Delay routines, using a pre-computed "loops_per_second" value.
  13 + */
  14 +#ifndef __UNICORE_DELAY_H__
  15 +#define __UNICORE_DELAY_H__
  16 +
  17 +#include <asm/param.h> /* HZ */
  18 +
  19 +extern void __delay(int loops);
  20 +
  21 +/*
  22 + * This function intentionally does not exist; if you see references to
  23 + * it, it means that you're calling udelay() with an out of range value.
  24 + *
  25 + * With currently imposed limits, this means that we support a max delay
  26 + * of 2000us. Further limits: HZ<=1000 and bogomips<=3355
  27 + */
  28 +extern void __bad_udelay(void);
  29 +
  30 +/*
  31 + * division by multiplication: you don't have to worry about
  32 + * loss of precision.
  33 + *
  34 + * Use only for very small delays ( < 1 msec). Should probably use a
  35 + * lookup table, really, as the multiplications take much too long with
  36 + * short delays. This is a "reasonable" implementation, though (and the
  37 + * first constant multiplications gets optimized away if the delay is
  38 + * a constant)
  39 + */
  40 +extern void __udelay(unsigned long usecs);
  41 +extern void __const_udelay(unsigned long);
  42 +
  43 +#define MAX_UDELAY_MS 2
  44 +
  45 +#define udelay(n) \
  46 + (__builtin_constant_p(n) ? \
  47 + ((n) > (MAX_UDELAY_MS * 1000) ? __bad_udelay() : \
  48 + __const_udelay((n) * ((2199023U*HZ)>>11))) : \
  49 + __udelay(n))
  50 +
  51 +#endif /* __UNICORE_DELAY_H__ */
arch/unicore32/include/asm/futex.h
  1 +/*
  2 + * linux/arch/unicore32/include/asm/futex.h
  3 + *
  4 + * Code specific to PKUnity SoC and UniCore ISA
  5 + *
  6 + * Copyright (C) 2001-2010 GUAN Xue-tao
  7 + *
  8 + * This program is free software; you can redistribute it and/or modify
  9 + * it under the terms of the GNU General Public License version 2 as
  10 + * published by the Free Software Foundation.
  11 + */
  12 +
  13 +#ifndef __UNICORE_FUTEX_H__
  14 +#define __UNICORE_FUTEX_H__
  15 +
  16 +#ifdef __KERNEL__
  17 +
  18 +#include <linux/futex.h>
  19 +#include <linux/preempt.h>
  20 +#include <linux/uaccess.h>
  21 +#include <linux/errno.h>
  22 +
  23 +#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
  24 + __asm__ __volatile__( \
  25 + "1: ldw.u %1, [%2]\n" \
  26 + " " insn "\n" \
  27 + "2: stw.u %0, [%2]\n" \
  28 + " mov %0, #0\n" \
  29 + "3:\n" \
  30 + " .pushsection __ex_table,\"a\"\n" \
  31 + " .align 3\n" \
  32 + " .long 1b, 4f, 2b, 4f\n" \
  33 + " .popsection\n" \
  34 + " .pushsection .fixup,\"ax\"\n" \
  35 + "4: mov %0, %4\n" \
  36 + " b 3b\n" \
  37 + " .popsection" \
  38 + : "=&r" (ret), "=&r" (oldval) \
  39 + : "r" (uaddr), "r" (oparg), "Ir" (-EFAULT) \
  40 + : "cc", "memory")
  41 +
  42 +static inline int
  43 +futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
  44 +{
  45 + int op = (encoded_op >> 28) & 7;
  46 + int cmp = (encoded_op >> 24) & 15;
  47 + int oparg = (encoded_op << 8) >> 20;
  48 + int cmparg = (encoded_op << 20) >> 20;
  49 + int oldval = 0, ret;
  50 +
  51 + if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
  52 + oparg = 1 << oparg;
  53 +
  54 + if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
  55 + return -EFAULT;
  56 +
  57 + pagefault_disable(); /* implies preempt_disable() */
  58 +
  59 + switch (op) {
  60 + case FUTEX_OP_SET:
  61 + __futex_atomic_op("mov %0, %3", ret, oldval, uaddr, oparg);
  62 + break;
  63 + case FUTEX_OP_ADD:
  64 + __futex_atomic_op("add %0, %1, %3", ret, oldval, uaddr, oparg);
  65 + break;
  66 + case FUTEX_OP_OR:
  67 + __futex_atomic_op("or %0, %1, %3", ret, oldval, uaddr, oparg);
  68 + break;
  69 + case FUTEX_OP_ANDN:
  70 + __futex_atomic_op("and %0, %1, %3",
  71 + ret, oldval, uaddr, ~oparg);
  72 + break;
  73 + case FUTEX_OP_XOR:
  74 + __futex_atomic_op("xor %0, %1, %3", ret, oldval, uaddr, oparg);
  75 + break;
  76 + default:
  77 + ret = -ENOSYS;
  78 + }
  79 +
  80 + pagefault_enable(); /* subsumes preempt_enable() */
  81 +
  82 + if (!ret) {
  83 + switch (cmp) {
  84 + case FUTEX_OP_CMP_EQ:
  85 + ret = (oldval == cmparg);
  86 + break;
  87 + case FUTEX_OP_CMP_NE:
  88 + ret = (oldval != cmparg);
  89 + break;
  90 + case FUTEX_OP_CMP_LT:
  91 + ret = (oldval < cmparg);
  92 + break;
  93 + case FUTEX_OP_CMP_GE:
  94 + ret = (oldval >= cmparg);
  95 + break;
  96 + case FUTEX_OP_CMP_LE:
  97 + ret = (oldval <= cmparg);
  98 + break;
  99 + case FUTEX_OP_CMP_GT:
  100 + ret = (oldval > cmparg);
  101 + break;
  102 + default:
  103 + ret = -ENOSYS;
  104 + }
  105 + }
  106 + return ret;
  107 +}
  108 +
  109 +static inline int
  110 +futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
  111 +{
  112 + int val;
  113 +
  114 + if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
  115 + return -EFAULT;
  116 +
  117 + pagefault_disable(); /* implies preempt_disable() */
  118 +
  119 + __asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n"
  120 + "1: ldw.u %0, [%3]\n"
  121 + " cmpxor.a %0, %1\n"
  122 + " bne 3f\n"
  123 + "2: stw.u %2, [%3]\n"
  124 + "3:\n"
  125 + " .pushsection __ex_table,\"a\"\n"
  126 + " .align 3\n"
  127 + " .long 1b, 4f, 2b, 4f\n"
  128 + " .popsection\n"
  129 + " .pushsection .fixup,\"ax\"\n"
  130 + "4: mov %0, %4\n"
  131 + " b 3b\n"
  132 + " .popsection"
  133 + : "=&r" (val)
  134 + : "r" (oldval), "r" (newval), "r" (uaddr), "Ir" (-EFAULT)
  135 + : "cc", "memory");
  136 +
  137 + pagefault_enable(); /* subsumes preempt_enable() */
  138 +
  139 + return val;
  140 +}
  141 +
  142 +#endif /* __KERNEL__ */
  143 +#endif /* __UNICORE_FUTEX_H__ */
arch/unicore32/include/asm/io.h
  1 +/*
  2 + * linux/arch/unicore32/include/asm/io.h
  3 + *
  4 + * Code specific to PKUnity SoC and UniCore ISA
  5 + *
  6 + * Copyright (C) 2001-2010 GUAN Xue-tao
  7 + *
  8 + * This program is free software; you can redistribute it and/or modify
  9 + * it under the terms of the GNU General Public License version 2 as
  10 + * published by the Free Software Foundation.
  11 + */
  12 +#ifndef __UNICORE_IO_H__
  13 +#define __UNICORE_IO_H__
  14 +
  15 +#ifdef __KERNEL__
  16 +
  17 +#include <asm/byteorder.h>
  18 +#include <asm/memory.h>
  19 +#include <asm/system.h>
  20 +
  21 +#include <asm-generic/io.h>
  22 +
  23 +/*
  24 + * __uc32_ioremap and __uc32_ioremap_cached takes CPU physical address.
  25 + */
  26 +extern void __iomem *__uc32_ioremap(unsigned long, size_t);
  27 +extern void __iomem *__uc32_ioremap_cached(unsigned long, size_t);
  28 +extern void __uc32_iounmap(volatile void __iomem *addr);
  29 +
  30 +/*
  31 + * ioremap and friends.
  32 + *
  33 + * ioremap takes a PCI memory address, as specified in
  34 + * Documentation/IO-mapping.txt.
  35 + *
  36 + */
  37 +#define ioremap(cookie, size) __uc32_ioremap(cookie, size)
  38 +#define ioremap_cached(cookie, size) __uc32_ioremap_cached(cookie, size)
  39 +#define iounmap(cookie) __uc32_iounmap(cookie)
  40 +
  41 +extern void __iomem *ioport_map(unsigned long port, unsigned int nr);
  42 +extern void ioport_unmap(void __iomem *addr);
  43 +
  44 +/*
  45 + * Convert a physical pointer to a virtual kernel pointer for /dev/mem
  46 + * access
  47 + */
  48 +#undef xlate_dev_mem_ptr
  49 +#define xlate_dev_mem_ptr(p) __va(p)
  50 +
  51 +#endif /* __KERNEL__ */
  52 +#endif /* __UNICORE_IO_H__ */
arch/unicore32/include/asm/mutex.h
  1 +/*
  2 + * linux/arch/unicore32/include/asm/mutex.h
  3 + *
  4 + * Code specific to PKUnity SoC and UniCore ISA
  5 + *
  6 + * Copyright (C) 2001-2010 GUAN Xue-tao
  7 + *
  8 + * This program is free software; you can redistribute it and/or modify
  9 + * it under the terms of the GNU General Public License version 2 as
  10 + * published by the Free Software Foundation.
  11 + *
  12 + * UniCore optimized mutex locking primitives
  13 + *
  14 + * Please look into asm-generic/mutex-xchg.h for a formal definition.
  15 + */
  16 +#ifndef __UNICORE_MUTEX_H__
  17 +#define __UNICORE_MUTEX_H__
  18 +
  19 +# include <asm-generic/mutex-xchg.h>
  20 +#endif
arch/unicore32/lib/Makefile
  1 +#
  2 +# linux/arch/unicore32/lib/Makefile
  3 +#
  4 +# Copyright (C) 2001-2010 GUAN Xue-tao
  5 +#
  6 +
  7 +lib-y := backtrace.o delay.o findbit.o
  8 +lib-y += strncpy_from_user.o strnlen_user.o
  9 +lib-y += clear_user.o copy_page.o
  10 +lib-y += copy_from_user.o copy_to_user.o
  11 +
  12 +GNU_LIBC_A := $(shell $(CC) $(KBUILD_CFLAGS) -print-file-name=libc.a)
  13 +GNU_LIBC_A_OBJS := memchr.o memcpy.o memmove.o memset.o
  14 +GNU_LIBC_A_OBJS += strchr.o strrchr.o
  15 +GNU_LIBC_A_OBJS += rawmemchr.o # needed by strrchr.o
  16 +
  17 +GNU_LIBGCC_A := $(shell $(CC) $(KBUILD_CFLAGS) -print-file-name=libgcc.a)
  18 +GNU_LIBGCC_A_OBJS := _ashldi3.o _ashrdi3.o _lshrdi3.o
  19 +GNU_LIBGCC_A_OBJS += _divsi3.o _modsi3.o _ucmpdi2.o _umodsi3.o _udivsi3.o
  20 +
  21 +lib-y += $(GNU_LIBC_A_OBJS) $(GNU_LIBGCC_A_OBJS)
  22 +
  23 +$(addprefix $(obj)/, $(GNU_LIBC_A_OBJS)):
  24 + $(Q)$(AR) p $(GNU_LIBC_A) $(notdir $@) > $@
  25 +
  26 +$(addprefix $(obj)/, $(GNU_LIBGCC_A_OBJS)):
  27 + $(Q)$(AR) p $(GNU_LIBGCC_A) $(notdir $@) > $@
arch/unicore32/lib/delay.S
  1 +/*
  2 + * linux/arch/unicore32/lib/delay.S
  3 + *
  4 + * Code specific to PKUnity SoC and UniCore ISA
  5 + *
  6 + * Copyright (C) 2001-2010 GUAN Xue-tao
  7 + *
  8 + * This program is free software; you can redistribute it and/or modify
  9 + * it under the terms of the GNU General Public License version 2 as
  10 + * published by the Free Software Foundation.
  11 + */
  12 +#include <linux/linkage.h>
  13 +#include <asm/assembler.h>
  14 +#include <asm/param.h>
  15 + .text
  16 +
  17 +.LC0: .word loops_per_jiffy
  18 +.LC1: .word (2199023*HZ)>>11
  19 +
  20 +/*
  21 + * r0 <= 2000
  22 + * lpj <= 0x01ffffff (max. 3355 bogomips)
  23 + * HZ <= 1000
  24 + */
  25 +
  26 +ENTRY(__udelay)
  27 + ldw r2, .LC1
  28 + mul r0, r2, r0
  29 +ENTRY(__const_udelay) @ 0 <= r0 <= 0x7fffff06
  30 + ldw r2, .LC0
  31 + ldw r2, [r2] @ max = 0x01ffffff
  32 + mov r0, r0 >> #14 @ max = 0x0001ffff
  33 + mov r2, r2 >> #10 @ max = 0x00007fff
  34 + mul r0, r2, r0 @ max = 2^32-1
  35 + mov.a r0, r0 >> #6
  36 + cmoveq pc, lr
  37 +
  38 +/*
  39 + * loops = r0 * HZ * loops_per_jiffy / 1000000
  40 + *
  41 + * Oh, if only we had a cycle counter...
  42 + */
  43 +
  44 +@ Delay routine
  45 +ENTRY(__delay)
  46 + sub.a r0, r0, #2
  47 + bua __delay
  48 + mov pc, lr
  49 +ENDPROC(__udelay)
  50 +ENDPROC(__const_udelay)
  51 +ENDPROC(__delay)
arch/unicore32/lib/findbit.S
  1 +/*
  2 + * linux/arch/unicore32/lib/findbit.S
  3 + *
  4 + * Code specific to PKUnity SoC and UniCore ISA
  5 + *
  6 + * Copyright (C) 2001-2010 GUAN Xue-tao
  7 + *
  8 + * This program is free software; you can redistribute it and/or modify
  9 + * it under the terms of the GNU General Public License version 2 as
  10 + * published by the Free Software Foundation.
  11 + */
  12 +#include <linux/linkage.h>
  13 +#include <asm/assembler.h>
  14 + .text
  15 +
  16 +/*
  17 + * Purpose : Find a 'zero' bit
  18 + * Prototype: int find_first_zero_bit(void *addr, unsigned int maxbit);
  19 + */
  20 +__uc32_find_first_zero_bit:
  21 + cxor.a r1, #0
  22 + beq 3f
  23 + mov r2, #0
  24 +1: ldb r3, [r0+], r2 >> #3
  25 + xor.a r3, r3, #0xff @ invert bits
  26 + bne .L_found @ any now set - found zero bit
  27 + add r2, r2, #8 @ next bit pointer
  28 +2: csub.a r2, r1 @ any more?
  29 + bub 1b
  30 +3: mov r0, r1 @ no free bits
  31 + mov pc, lr
  32 +
  33 +/*
  34 + * Purpose : Find next 'zero' bit
  35 + * Prototype: int find_next_zero_bit
  36 + * (void *addr, unsigned int maxbit, int offset)
  37 + */
  38 +ENTRY(__uc32_find_next_zero_bit)
  39 + cxor.a r1, #0
  40 + beq 3b
  41 + and.a ip, r2, #7
  42 + beq 1b @ If new byte, goto old routine
  43 + ldb r3, [r0+], r2 >> #3
  44 + xor r3, r3, #0xff @ now looking for a 1 bit
  45 + mov.a r3, r3 >> ip @ shift off unused bits
  46 + bne .L_found
  47 + or r2, r2, #7 @ if zero, then no bits here
  48 + add r2, r2, #1 @ align bit pointer
  49 + b 2b @ loop for next bit
  50 +ENDPROC(__uc32_find_next_zero_bit)
  51 +
  52 +/*
  53 + * Purpose : Find a 'one' bit
  54 + * Prototype: int find_first_bit
  55 + * (const unsigned long *addr, unsigned int maxbit);
  56 + */
  57 +__uc32_find_first_bit:
  58 + cxor.a r1, #0
  59 + beq 3f
  60 + mov r2, #0
  61 +1: ldb r3, [r0+], r2 >> #3
  62 + mov.a r3, r3
  63 + bne .L_found @ any now set - found zero bit
  64 + add r2, r2, #8 @ next bit pointer
  65 +2: csub.a r2, r1 @ any more?
  66 + bub 1b
  67 +3: mov r0, r1 @ no free bits
  68 + mov pc, lr
  69 +
  70 +/*
  71 + * Purpose : Find next 'one' bit
  72 + * Prototype: int find_next_zero_bit
  73 + * (void *addr, unsigned int maxbit, int offset)
  74 + */
  75 +ENTRY(__uc32_find_next_bit)
  76 + cxor.a r1, #0
  77 + beq 3b
  78 + and.a ip, r2, #7
  79 + beq 1b @ If new byte, goto old routine
  80 + ldb r3, [r0+], r2 >> #3
  81 + mov.a r3, r3 >> ip @ shift off unused bits
  82 + bne .L_found
  83 + or r2, r2, #7 @ if zero, then no bits here
  84 + add r2, r2, #1 @ align bit pointer
  85 + b 2b @ loop for next bit
  86 +ENDPROC(__uc32_find_next_bit)
  87 +
  88 +/*
  89 + * One or more bits in the LSB of r3 are assumed to be set.
  90 + */
  91 +.L_found:
  92 + rsub r1, r3, #0
  93 + and r3, r3, r1
  94 + cntlz r3, r3
  95 + rsub r3, r3, #31
  96 + add r0, r2, r3
  97 + mov pc, lr