Skip to content

Bitmask Generator & Register Workbench

Build, paste and visualize bitmasks at 8, 16, 32 or 64 bits - then generate the set, clear, toggle and field-extract code for them.

Register width
Or pick a bit range

Click a bit to add or remove it from the mask · MSB (bit 31) left → LSB (bit 0) right

Hex0x000000F0
Decimal240
Octal0o360
Inverted (~mask)0xFFFFFF0F
Binary (32-bit)0000 0000 0000 0000 0000 0000 1111 0000
Bits set
4
Ranges
[7:4]
Shift (LSB)
4
Field capacity
4-bit, max 15

Presets

Masks lifted straight from datasheets and runtimes - load one, then adjust the bits.

Emitted as FIELD_MASK

Code for this mask

Regenerated from the mask above on every change - never a canned 0xF0 example.

/* 32-bit mask over bits [7:4] */
#define FIELD_MASK   0x000000F0u
#define FIELD_SHIFT  4u

uint32_t reg = 0;

reg |=  FIELD_MASK;                 /* set   */
reg &= ~FIELD_MASK;                 /* clear */
reg ^=  FIELD_MASK;                 /* toggle */

/* read the field, right-aligned */
uint32_t value = (reg & FIELD_MASK) >> FIELD_SHIFT;

/* write the field without disturbing the other bits */
reg = (reg & ~FIELD_MASK) | ((value << FIELD_SHIFT) & FIELD_MASK);

Practical examples

Configuring an STM32 GPIO pin

GPIOx_MODER packs two bits per pin, so pin n lives at bits [2n+1 : 2n]. For pin 5 that is [11:10], mask 0x00000C00, shift 10. You cannot just OR the mode in: the field already holds the reset value, so it has to be cleared first. That is exactly the read-modify-write the Write field operation generates - MODER = (MODER & ~0xC00) | (0x1 << 10) puts the pin in general-purpose output mode without disturbing the other fifteen pins.

Enabling an AVR USART

UCSR0B holds RXEN0 at bit 4 and TXEN0 at bit 3. Enabling both is a single set: UCSR0B |= (1 << RXEN0) | (1 << TXEN0), which is mask 0x18. Because it is an OR, the interrupt-enable bits already in the register survive - the reason firmware never writes a whole register with = unless it means to reset every field in it.

Building a DPDK or taskset core mask

Core affinity masks are one bit per logical CPU, so cores 0-3 are 0xF and cores 8-11 are 0xF00. Set the register width to 64 and click the cores you want - a 96-core box needs two masks, because the bit index is the core number and nothing above 63 fits in a single 64-bit word.

Unpacking a packed colour or flags word

A 0x00RRGGBB pixel is three 8-bit fields: red is 0x00FF0000 shift 16, green 0x0000FF00 shift 8, blue 0x000000FF shift 0. Describe it once in the Struct layout tab (blue, green, red, alpha at 8 bits each) and the generated accessors do the shifting for you.

How bitmasks work

A bitmask is an integer used as a stencil. Every position that is 1 in the mask selects a bit in the target value; every 0 leaves the corresponding bit alone. That one idea gives you four operations, and firmware, kernels, protocol parsers and permission systems are built almost entirely out of them.

  • Set with reg |= mask. OR can only turn bits on, so unmasked bits are untouched.
  • Clear with reg &= ~mask. The inversion is the important half: AND against a mask of mostly ones keeps everything except the selected bits.
  • Toggle with reg ^= mask. XOR flips exactly the masked bits, which is how you blink an LED without reading the port back first.
  • Read with (reg & mask) >> shift. Masking isolates the field; the shift right-aligns it so you get 3 rather than 0x300.

Writing a multi-bit field is the composite of clear and set: reg = (reg & ~mask) | ((value << shift) & mask). The trailing & mask is not decoration - it stops an oversized value from spilling into the neighbouring field, which is the single most common bit-field bug.

Language gotchas

JavaScript truncates to 32 bits

&, |, ^ and << coerce their operands to signed 32-bit integers, so 1 << 31 is negative and 1 << 32 is 1. Use BigInt literals for anything wider - this page does, which is why the 64-bit masks above stay exact.

Python integers are unbounded

~0xF0 is -241, not 0xFFFFFF0F. Always AND the inverted mask back down to the register width: reg &= ~MASK & 0xFFFFFFFF.

C promotes to int

1 << 31 on a 32-bit int is undefined behaviour, and ~mask on a uint8_t promotes to int first. Write 1u << 31, 1ULL << 40, and keep register variables in explicit uintN_t types.

Rust panics on overflowing shifts

Shifting a u32 by 32 or more panics in debug and is masked to shift % 32 in release. Use checked_shl or wrapping_shl when the amount is not a constant.

Mask reference

Right-aligned masks of every common field width, the values you reach for when a datasheet says “n-bit field”.

BitsRangeHex (32-bit)DecimalMax field value
1[0:0]0x0000000111
2[1:0]0x0000000333
3[2:0]0x0000000777
4[3:0]0x0000000F1515
5[4:0]0x0000001F3131
6[5:0]0x0000003F6363
7[6:0]0x0000007F127127
8[7:0]0x000000FF255255
12[11:0]0x00000FFF40954095
16[15:0]0x0000FFFF6553565535
24[23:0]0x00FFFFFF1677721516777215
32[31:0]0xFFFFFFFF42949672954294967295

Frequently Asked Questions

What is a bitmask?

A bitmask is an integer used as a stencil. Every bit that is 1 in the mask selects the matching bit in a target value, and every 0 leaves that bit alone. Masks are how firmware, kernels, protocol parsers and permission systems address individual bits inside a word.

How do I create a bitmask for a range of bits?

For an N-bit field starting at position P the mask is ((1 << N) - 1) << P. A 4-bit field at position 4 gives ((1 << 4) - 1) << 4 = 0xF0. Use the start-bit and length inputs above and the tool computes it, along with the shift you need to right-align the field.

How do I convert a number like 15 to a bitmask?

Paste it into the mask value box - 15, 0xF and 0b1111 all describe the same mask, bits [3:0]. The bit grid lights up the bits that value covers, and the readouts give you the hex, decimal, octal and binary forms plus the inverted mask.

Can I paste an existing hex mask and see which bits it targets?

Yes. Paste 0x02, 0xFF00, 0b1010 or a plain decimal into the mask value field and the grid highlights exactly the bits that mask covers, with the ranges printed in datasheet notation such as [15:8].

How do I set, clear or toggle bits with a mask?

Set with reg |= mask (OR can only turn bits on), clear with reg &= ~mask (AND against the inverted mask), and toggle with reg ^= mask (XOR flips exactly the masked bits). The Register operations tab applies each one to a value you supply and shows the before and after bit patterns with the changed bits highlighted.

How do I read a multi-bit field out of a register?

Mask it, then shift it right by the position of the mask's lowest set bit: value = (reg & mask) >> shift. Without the shift you get the field still sitting in place, so a 3 in bits [9:8] reads as 0x300 rather than 3.

How do I write a field without disturbing the other bits?

Clear then set in one expression: reg = (reg & ~mask) | ((value << shift) & mask). The trailing & mask matters - it stops an oversized value spilling into the neighbouring field, which is the most common bit-field bug.

Does this support 64-bit masks?

Yes, at 8, 16, 32 and 64 bits. Every value is computed with BigInt, so 64-bit masks are exact. That matters because JavaScript's own bitwise operators coerce to signed 32-bit integers, which silently breaks any hand-rolled 64-bit mask in the browser console.

What is a core mask or lcore mask?

A CPU affinity mask: one bit per logical core, so cores 0-3 are 0xF and cores 8-11 are 0xF00. DPDK's -c coremask, taskset and sched_setaffinity all take this form. Switch to 64-bit and click the cores you want.

Why is ~mask wrong in Python?

Python integers are unbounded, so ~0xF0 is -241 rather than 0xFFFFFF0F. You have to AND the inverted mask back down to the register width: reg &= ~MASK & 0xFFFFFFFF. The generated Python above already does this.

Can it generate C bit-field structs?

Yes. The Struct layout tab takes named fields with widths, packs them from bit 0 upwards, and emits the mask and shift #defines plus a union of the raw word and a C bit-field struct, along with Rust and Python equivalents. Prefer the macros for real hardware: C bit-field ordering is implementation-defined.

What happens with a non-contiguous mask?

Set, clear and toggle still work exactly - they are per-bit operations. But a single shift cannot right-align a field split across two runs of bits, so the tool flags the mask as non-contiguous and lists each run separately.

Related Tools

This tool runs entirely in your browser - nothing you enter is uploaded or stored.