#ifndef _ASM_GENERIC_BITOPS_H_
|
#ifndef _ASM_GENERIC_BITOPS_H_
|
#define _ASM_GENERIC_BITOPS_H_
|
#define _ASM_GENERIC_BITOPS_H_
|
|
|
#include <asm/system.h>
|
#include <asm/system.h>
|
|
|
/*
|
/*
|
* N.B.: we shouldn't assume addresses are long*'s; nr can be > 31.
|
* N.B.: we shouldn't assume addresses are long*'s; nr can be > 31.
|
*/
|
*/
|
static __inline__ long set_bit(long nr, void *a)
|
static __inline__ long set_bit(long nr, void *a)
|
{
|
{
|
long* addr = a;
|
long* addr = a;
|
int mask, oldval;
|
int mask, oldval;
|
|
|
addr += nr >> 5;
|
addr += nr >> 5;
|
mask = 1 << (nr & 0x1f);
|
mask = 1 << (nr & 0x1f);
|
__asm__ __volatile__
|
__asm__ __volatile__
|
("atmod %3, %2, %2"
|
("atmod %3, %2, %2"
|
: "=m" (*addr), "=r" (oldval)
|
: "=m" (*addr), "=r" (oldval)
|
: "1" (mask), "r" (addr), "m"(*addr));
|
: "1" (mask), "r" (addr), "m"(*addr));
|
return (oldval & mask) != 0;
|
return (oldval & mask) != 0;
|
}
|
}
|
|
|
static __inline__ long clear_bit(long nr, void *a)
|
static __inline__ long clear_bit(long nr, void *a)
|
{
|
{
|
long* addr = a;
|
long* addr = a;
|
int mask, oldval;
|
int mask, oldval;
|
|
|
addr += nr >> 5;
|
addr += nr >> 5;
|
mask = 1 << (nr & 0x1f);
|
mask = 1 << (nr & 0x1f);
|
__asm__ __volatile__
|
__asm__ __volatile__
|
("atmod %4, %3, %2"
|
("atmod %4, %3, %2"
|
: "=m" (*addr), "=r"(oldval)
|
: "=m" (*addr), "=r"(oldval)
|
: "1" (0), "r" (mask), "r"(addr), "m"(*addr));
|
: "1" (0), "r" (mask), "r"(addr), "m"(*addr));
|
return (oldval & mask) != 0;
|
return (oldval & mask) != 0;
|
}
|
}
|
|
|
|
|
static __inline__ long change_bit(long nr, void *a)
|
static __inline__ long change_bit(long nr, void *a)
|
{
|
{
|
long* addr = a;
|
long* addr = a;
|
long flags;
|
long flags;
|
int bitpos, retval;
|
int bitpos, retval;
|
|
|
addr += nr >> 5;
|
addr += nr >> 5;
|
bitpos = (nr & 0x1f);
|
bitpos = (nr & 0x1f);
|
save_flags(flags);
|
save_flags(flags);
|
cli();
|
cli();
|
|
|
#if 1
|
#if 1
|
retval = (*addr & (1 << bitpos));
|
retval = (*addr & (1 << bitpos));
|
*addr ^= (1 << bitpos);
|
*addr ^= (1 << bitpos);
|
#else
|
#else
|
__asm__
|
__asm__
|
("ld (%2), r3\n\t"
|
("ld (%2), r3\n\t"
|
"notbit %1, r3, r4\n\t"
|
"notbit %1, r3, r4\n\t"
|
"st r4, (%2)\n\t"
|
"st r4, (%2)\n\t"
|
"ldconst 1, r4\n\t"
|
"ldconst 1, r4\n\t"
|
"shlo %1, r4, r4\n\t"
|
"shlo %1, r4, r4\n\t"
|
"and r4, r3, %0\n\t"
|
"and r4, r3, %0\n\t"
|
: "=&r" (retval)
|
: "=&r" (retval)
|
: "r" (bitpos), "r" (addr)
|
: "r" (bitpos), "r" (addr)
|
: "r3", "r4", "memory");
|
: "r3", "r4", "memory");
|
#endif
|
#endif
|
restore_flags(flags);
|
restore_flags(flags);
|
return retval != 0;
|
return retval != 0;
|
}
|
}
|
|
|
static __inline__ long test_bit(long nr, void *a)
|
static __inline__ long test_bit(long nr, void *a)
|
{
|
{
|
int * addr = a;
|
int * addr = a;
|
int mask;
|
int mask;
|
|
|
addr += nr >> 5;
|
addr += nr >> 5;
|
mask = 1 << (nr & 0x1f);
|
mask = 1 << (nr & 0x1f);
|
return ((mask & *addr) != 0);
|
return ((mask & *addr) != 0);
|
}
|
}
|
|
|
/* The easy/cheese version for now. */
|
/* The easy/cheese version for now. */
|
extern __inline__ unsigned long ffz(unsigned long word)
|
extern __inline__ unsigned long ffz(unsigned long word)
|
{
|
{
|
unsigned long result = 0;
|
unsigned long result = 0;
|
|
|
while(word & 1) {
|
while(word & 1) {
|
result++;
|
result++;
|
word >>= 1;
|
word >>= 1;
|
}
|
}
|
return result;
|
return result;
|
}
|
}
|
|
|
/* find_next_zero_bit() finds the first zero bit in a bit string of length
|
/* find_next_zero_bit() finds the first zero bit in a bit string of length
|
* 'size' bits, starting the search at bit 'offset'. This is largely based
|
* 'size' bits, starting the search at bit 'offset'. This is largely based
|
* on Linus's ALPHA routines, which are pretty portable BTW.
|
* on Linus's ALPHA routines, which are pretty portable BTW.
|
*/
|
*/
|
|
|
extern __inline__ unsigned long find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
|
extern __inline__ unsigned long find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
|
{
|
{
|
unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
|
unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
|
unsigned long result = offset & ~31UL;
|
unsigned long result = offset & ~31UL;
|
unsigned long tmp;
|
unsigned long tmp;
|
|
|
if (offset >= size)
|
if (offset >= size)
|
return size;
|
return size;
|
size -= result;
|
size -= result;
|
offset &= 31UL;
|
offset &= 31UL;
|
if (offset) {
|
if (offset) {
|
tmp = *(p++);
|
tmp = *(p++);
|
tmp |= ~0UL >> (32-offset);
|
tmp |= ~0UL >> (32-offset);
|
if (size < 32)
|
if (size < 32)
|
goto found_first;
|
goto found_first;
|
if (~tmp)
|
if (~tmp)
|
goto found_middle;
|
goto found_middle;
|
size -= 32;
|
size -= 32;
|
result += 32;
|
result += 32;
|
}
|
}
|
while (size & ~31UL) {
|
while (size & ~31UL) {
|
if (~(tmp = *(p++)))
|
if (~(tmp = *(p++)))
|
goto found_middle;
|
goto found_middle;
|
result += 32;
|
result += 32;
|
size -= 32;
|
size -= 32;
|
}
|
}
|
if (!size)
|
if (!size)
|
return result;
|
return result;
|
tmp = *p;
|
tmp = *p;
|
|
|
found_first:
|
found_first:
|
tmp |= ~0UL >> size;
|
tmp |= ~0UL >> size;
|
found_middle:
|
found_middle:
|
return result + ffz(tmp);
|
return result + ffz(tmp);
|
}
|
}
|
|
|
/* Linus sez that gcc can optimize the following correctly, we'll see if this
|
/* Linus sez that gcc can optimize the following correctly, we'll see if this
|
* holds on the Sparc as it does for the ALPHA.
|
* holds on the Sparc as it does for the ALPHA.
|
*/
|
*/
|
|
|
#define find_first_zero_bit(addr, size) \
|
#define find_first_zero_bit(addr, size) \
|
find_next_zero_bit((addr), (size), 0)
|
find_next_zero_bit((addr), (size), 0)
|
|
|
|
|
#endif /* _ASM_I960_BITOPS_H */
|
#endif /* _ASM_I960_BITOPS_H */
|
|
|