Bit Basics Monday
Seairth
Posts: 2,474
(Because this came up in another post, I figured I would touch on it briefly. Maybe it will help new programmers that come through these forums. And "Monday" doesn't really have anything to do with it, but it sounded good. )
When you are working with an array of bits (e.g. flags, signals, memory-mapped I/O, etc), there are three basic operations that you typically perform:
In many languages, there are three corresponding operators or instructions that allow you to perform those actions. All of these operators depend on two operands:
The mask bit array is simple. For each bit in the source array that you want to change, set the same bit (same index) in the mask array to 1 (one). Set all other bits to 0 (zero). For instance, a mask array of "01100100" would indicate that you want to change bits 2, 5, and 6. It also indicates that you do not want to change bits 0, 1, 3, 4, and 7.
SET
The operator to use is "OR". For each bit that's set in the mask, the corresponding bit in source will be set (x OR 1 is always 1). For each bit that's not set in the mask, the corresponding bit in source will be unchanged (x OR 0 is always x).
BS1/BS2
Spin
PASM
CLEAR
The operator to use is "ANDN". For each bit that's set in the mask, the corresponding bit will be cleared in source. The reason is that the mask is first inverted (NOT) before it is applied to source with AND. Therefore, all the original mask bits that were set are now zero, which will result in the matching source bits being set to zero (x AND 0 is always 0). Conversely, all the original mask bits that were not set are now one, which will result in the matching source bits being unchanged (x AND 1 is always x).
BS1
Spin
PASM
TOGGLE
The operator to use is "XOR". For each bit that's set in the mask, the corresponding bit in source will toggle (x XOR 1 is always "NOT x"). For each bit that's not set in the mask, the corresponding bit in source will be unchanged (x XOR 0 is always x).
BS1/BS2
Spin
PASM
I hope someone finds this useful. Personally, it was many years before I realized that XOR could be thought of as a conditional toggle operator. If nothing else, maybe this will save others a bit of time discovering that one.
When you are working with an array of bits (e.g. flags, signals, memory-mapped I/O, etc), there are three basic operations that you typically perform:
- set
- clear
- toggle
In many languages, there are three corresponding operators or instructions that allow you to perform those actions. All of these operators depend on two operands:
- The source bit array that needs to be changed
- A mask bit array that indicates which bit or bits to change.
The mask bit array is simple. For each bit in the source array that you want to change, set the same bit (same index) in the mask array to 1 (one). Set all other bits to 0 (zero). For instance, a mask array of "01100100" would indicate that you want to change bits 2, 5, and 6. It also indicates that you do not want to change bits 0, 1, 3, 4, and 7.
SET
The operator to use is "OR". For each bit that's set in the mask, the corresponding bit in source will be set (x OR 1 is always 1). For each bit that's not set in the mask, the corresponding bit in source will be unchanged (x OR 0 is always x).
BS1/BS2
src = src | mask
Spin
src := src | mask
src |= mask ' shorthand variation
PASM
or src, mask
CLEAR
The operator to use is "ANDN". For each bit that's set in the mask, the corresponding bit will be cleared in source. The reason is that the mask is first inverted (NOT) before it is applied to source with AND. Therefore, all the original mask bits that were set are now zero, which will result in the matching source bits being set to zero (x AND 0 is always 0). Conversely, all the original mask bits that were not set are now one, which will result in the matching source bits being unchanged (x AND 1 is always x).
Note: the value of mask is not actually altered by the operation, only source.
BS1
src = src &/ mask
Spin
src := src & (!mask)
src &= (!mask) ' shorthand variation
PASM
andn src, mask
TOGGLE
The operator to use is "XOR". For each bit that's set in the mask, the corresponding bit in source will toggle (x XOR 1 is always "NOT x"). For each bit that's not set in the mask, the corresponding bit in source will be unchanged (x XOR 0 is always x).
BS1/BS2
src = src ^ mask
Spin
src := src ^ mask
src ^= mask ' shorthand variation
PASM
xor src, mask
Note: One thing you need to be careful about when using XOR is that you must be sure that you know what the current state of the source bits are. OR and ANDN will set or clear the bits regardless of their original value, while XOR is dependent on the original value. As a result, OR and ANDN are best used for explicitly setting/clearing bits (think "I want to turn X on/off"). XOR, on the other hand, is best used for things like pulse trains (think "I want to toggle the clock edge every x microsecdonds") and code snippets that would otherwise look like:
' SPIN if source & mask ' is the bit set? source &= (!mask) ' clear the bit (ANDN) else source |= mask ' otherwise, set the bit (OR)
' PASM test source, mask ' is the bit set? if_nz andn source, mask ' clear the bit if_z or source, mask ' otherwise, set the bit
I hope someone finds this useful. Personally, it was many years before I realized that XOR could be thought of as a conditional toggle operator. If nothing else, maybe this will save others a bit of time discovering that one.
Comments
SET: src = src | mask;
CLEAR: src = src & ^mask;
TOGGLE: src = src ^ mask;
Clear : src &= ~(mask); shorthand for ANDN, use () around mask incase for example ~(BIT0 | BIT2) without it the ~ only apply to the first one
TOGGLE: src ^= mask; shorthand for XOR