Bitwise Operations and Masks: Byte Control Bit by Bit

A byte is eight independent switches living in one cell. How do you reach a single one of them without touching the rest? That is what bitwise operations are for: AND, OR and XOR are applied to a byte element by element, and the number paired with them is called a mask. Masks appear twice in the course: in the bus gates (BusAND/BusOR) and in the level 2.23 gamepad program.

byte mask operation result effect 00000101 11111011 AND 00000001 bit 1 cleared 00000101 00000010 OR 00000111 bit 1 set 00000101 00000010 XOR 00000111 bit 1 toggled 00000101 00000100 AND 00000100 bit 2 was 1 — test passed A mask is a stencil: ones mean "pass through / modify", zeros mean "leave alone" (the other way around for AND)
Four classic tricks: AND with "almost zero" clears a bit, OR with a one sets it, XOR toggles it, AND with a single one tests it

Bitwise means element-wise

Ordinary addition links places together through carries. Bitwise operations do not: each pair of bits (byte, mask) is processed independently. In the i-th place of the result you get exactly what the operation's truth table yields for the i-th bits of the operands. That is why the bus versions of the gates in the course are simply eight ordinary gates side by side (in Verilog — a generate-for from level 4.37).

The tables are familiar: AND gives 1 only on two ones, OR — if there is at least one, XOR — when the bits differ. Not "numbers" but eight independent mini-computations.

A mask is a stencil for a byte

A mask is the second operand, chosen so that the needed places change and the rest do not. Four basic tricks for working with bit number k:

Set (make 1): X OR (1 << k). The mask's ones "paint" ones over the byte.
Clear (make 0): X AND NOT(1 << k) — a mask of all ones except position k. Remember 0xFE from the bus article? That is the mask "everything but the last bit".
Toggle: X XOR (1 << k). XOR with a one always flips the bit.
Test: X AND (1 << k). Non-zero result — the bit was 1; zero — it was 0.

The gamepad: reading buttons with masks

Level 2.23, "Gamepad", reads the buttons from port 254: the answer brings eight bits — one per button (1 — Up, 2 — Down, 4 — Left, 8 — Right). How do you find out whether "Left" is pressed? Apply the mask 4:

LDA 0        ; clear the accumulator
ADD 254      ; Acc = the button byte, e.g. 00000101 (Up + Left = 1 + 4 = 5)
AND 4        ; mask 00000100 — keep only the Left bit
JZ skip      ; zero? button not pressed — jump
...          ; we land here if Left is pressed
skip: HLT

Three lines — and the program "probes" one specific bit of an eight-bit byte. The same trick drives the snake on the Part 2 finale: polling buttons, checking directions, moving coordinates — all on AND masks and the flag jumps from the previous article.

Test yourself

Which operation sets bit 3 without touching the others?

OR with the mask 00001000: a one is "painted" into the right place, and OR does not change the remaining bits.

Why does AND 0xFF leave a byte unchanged while AND 0x00 wipes it?

AND with a one leaves the bit as-is; AND with a zero always gives 0. The mask 0xFF is all ones, 0x00 is all zeros.

What makes XOR useful for bit work?

It toggles: XOR with 1 flips the bit, XOR with 0 leaves it. Applying it twice restores everything.

Try it in the simulator →