Shop OBEX P1 Docs P2 Docs Learn Events
Bit Basics Monday — Parallax Forums

Bit Basics Monday

(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:
  • 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

  • I would just add the "C" language equivalents:

    SET: src = src | mask;
    CLEAR: src = src & ^mask;
    TOGGLE: src = src ^ mask;
  • Seairth, that was a refreshingly succinct and clear message. Thank you! The suggestion by tomcrawford is nice frosting on that admittedly small but extremely important cake.
  • tonyp12tonyp12 Posts: 1,951
    edited 2015-09-03 21:08
    >I would just add the "C" language equivalents:

    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
  • Also, what would bitwise-not be for BS2? I've never used it, and I didn't see an obvious operator.
Sign In or Register to comment.