Examples
of Using Bitwise Instructions
Andreas Moshovos, Jan 2024
Here we discuss several example uses of the bitwise and shift instructions. We will present these as C functions first and then we will be discussing their implementation in NIOS II assembly.
Extracting
a single bit from an input value
unsigned int
bit_read(unsigned int a, unsigned int index)
{
unsigned
int mask = (1<< index);
if
(a & mask) return 1;
return
0;
}
This function returns the bit at position “index” from the input value “a”. The bits are numbered, left to right 0 to 31. An equivalent code in assembly is. Recall r4 is a and r5 is index and the return value goes into r2:
bit_read:
movi r2, 1 # r2 = 1 // use r2 as temporary
sll r5, r2, r5 # mask = r5 = (1 << index)
and r2, r5, r4 # r2 = only the bit at index position from a
cmpne r2, r2, r0 # convert that to 0 or 1
ret
The shift instruction moves the 1 at the index position. Then the and instruction zeroes out all other bits from the input value in r4 except the one that is at the index position. The result in r2 is has 0s at all bit positions except at the index position. The bit at the index position can be 0 or 1 and its value is what a had at the same bit position. Here we take advantage of the fact that (a AND 1) = a. This is called “masking” we are masking out all other bits except the bit in position index. ANDing with a value that has 1s at some positions allows us to “extract” only those bits from the input. E.g., ANDing with 0xF allows us to “keep” only the last 4 bits of the input. We will use this often when communicating with devices.
Setting a
single bit of an input value to either 0 or 1
unsigned
int
bit_write(unsigned
int a, unsigned index, unsigned int value)
{
unsigned
int mask = (1 << index);
a = a &
(~mask); // zero out just the bit at index
mask =
((value & 1) << index); // the lower bit of value, is what we
// want the bit at index to be
// shift that into
position (index)
a = a |
mask; // OR it with the
existing value
// recall we kept
all bits as they were
// and zeroed out
just the bit at index
return a;
}
The code is as follows:
bit_write:
movi r2, -2 # r2 = 0xFFFFFFFE, zero at bit #0 all
others are 1
rol r2, r2, r5 # Place 0 at bit #index all others are 1
and r4, r5, r4 # Zero out the bit #index of the input in r4
andi r6, r6, 1 # extract
bit #0 from value what we want the bit
# #index to be
sll r2, r6, r5 # shift that to position index
or r2, r2,
r4 # or it with the input value
(which had bit #index
# zeroed out)
ret
Toggling
a bit
unsigned
int
bit_toggle(unsigned
int a, unsigned int index)
{
return a ^
(1 << index);
}
The code is as follows:
bit_toggle:
movi r2, 1
sll r2, r2, r5 # r2 = (1 << index)
xor r2, r2, r4 # r2 = a ^ (1 << index)
ret
Setting a
bit to 1
unsigned
int
bit_set(unsigned
int a, unsigned int index)
{
return a |
(1 << index);
}
Translates to:
bit_toggle:
movi r2, 1
sll r2, r2, r5 # r2 = (1 << index)
or r2, r2, r4 # r2 = a | (1 << index)
ret
Setting a
bit to 0
unsigned
int
bit_clear(unsigned
int a, unsigned int index)
{
return a
& ~(1 << index);
}
Translates to:
bit_write:
movi r2, -2 # r2 = 0xFFFFFFFE, zero at bit #0 all
others are 1
rol r2, r2, r5 # Place 0 at bit #index all others are 1
and r2, r2, r4 # Zero out the bit #index of the input in r4
ret
Find the
leading 1 bit: Position where there is the leftmost bit that is 1
unsigned
int
bit_leadone(unsigned
int a)
{
int t = (1 << 31);
int i = 31;
if (a == 0)
return 32;
while ((a
& t) == 0) {
t = t >> 1;
i--;
}
return i;
}
The code is as follows:
bit_leadone:
movi r2, 32
blt r4, r0, done
# input is 0, return 32, no leading 1
movi r2, 31
movhi r5, 0x8000
# r5 = t = (1<<31)
loop: and
r6, r4, r5 # r6 = value & r5
bne r6, r0, done # if non-zero found the leading one
slli r5, r5, 1 # t = t >> 1
addi r2, r2, -1 # i--
br loop
done:
ret