Bit Manipulation
Manipulating and Testing Bits
Remember the logical operators: AND, OR, NOT, XOR. Since each bit is essentially a boolean value, these can be applied as bit operators, too.
AVR instructions: AND, ANDI, OR, ORI, EOR, COM, and NEG
Shifts and Rotates
There are a variety of instructions that move bits through a register, called shifts and rotates. These instructions shift the bit values in a register one position either left or right -- that is, bit 3 gets the value of bit 2 in a left shift, and it gets the value of bit 4 in a right shift. Well, the question comes up as to what to do with the last bit on either side -- i.e., if we are shifting left, what value do we give bit 0? And what do we do with the value of bit 7? Just throw it away? Well, that is why there are different kinds of shifts and rotates.
The rotate instructions ROL, ROR treat the register like a circle, except that they use a 9th bit as well -- the Carry bit of the SREG register. So, ROL shifts all the bits left (up one position), takes the value of the Carry bit, and copies it to bit 0, and copies the value of bit 7 into the Carry bit. ROR does exactly the opposite, it copies the C bit to bit 7, and copies bit 0 to the C bit.
A logical shift instruction pushes a 0 bit value into the end that needs a bit value, and it copies the bit being shifted out into the Carry bit. Thus, LSL (logical shift left) sets bit 0 to the value 0, and copies bit 7 to the Carry bit. An LSR instruction sets bit 7 to 0, and copies bit 0 to the C bit.
An arithmetic shift instruction preserves the sign of a 2C number. To do this when shifting right, bit 7 (the sign bit) is copied back to itself, while also being shifted to bit 6. For the ASR, bit 0 is copied to the Carry bit. Well, what about an arithmetic shift left? What should we do with bit 7, the sign bit? It turns out that an ASL instruction would be exactly the same as the LSL instruction. Some CPUs allow both mnemonics to be used for the same machine instruction, but the AVR does not have the ASL mnemonic, only the LSL.
So, what use are the shift instructions? One of the most common uses is a fast way to multiply and divide. A shift left will multiple a number by two -- think about what happens to base ten numbers when you multiply by ten -- all the digits move over one place, and a 0 is added (e.g., 123*10 == 1230). The same is true for base two numbers when multiplying by two -- the bit values just shift one place left, and a 0 bit is added to the right.
If shift left multiplies, then shift right divides by two. And it does. But in this case we need to know if our number is unsigned or is a signed 2C number. If it is unsigned, we need to use LSR. If it is signed, we need to use ASR.
Setting and Testing Individual Bits
You can use the AND and OR instructions to manipulate and test individual bits, but these operations modify the value, and sometimes you just want to check bits without modifying the value.
The AVR has four special "bit test and branch" instructions:
- SBRC: Skip if Bit in Register is Clear: skips the next instruction if the specified bit in the specified register is 0.
- SBRS: Skip if Bit in Register is Set: skips the next instruction if the specified bit in the specified register is 1.
- SBIC: Skip if Bit in I/O Port is Clear: skips the next instruction if the specified bit in the specified I/O address is 0.
- SBIS: Skip if Bit in I/O Port is Set: skips the next instruction if the specified bit in the specified I/O address is 1.
These instructions cannot be made to branch anywhere, they can only be used to skip the instruction following the bit test instruction. Of course, that instruction can be an RJMP that can jump anywhere!
Using AND and OR as bit masking operations
THIS SECTION IS STILL TODO.…
Setting and clearing individual bits: examples
An easier way: setting and clearing bits directly in memory: BSET and BCLR
BSET <MemoryLoc> <Mask> -- sets bits in M[loc] that are 1's in the mask
- how? It OR's the mask with the memory location, and stores the result
BCLR <MemoryLoc> <Mask> -- clears bits in M[loc] that are 1's in mask (note)
- how? it AND's the complement of the mask with the memory location, and stores the result