Parsing a sequence of bits out of a bit field

For homework, I had to parse CPUID instruction output in C, which required a lot of specific bit-manipulation like:

(eax & CACHE_LEVEL) >> 5


I calculated the mask CACHE_LEVEL and the amount that was needed to be right-shifted by hand. It was a pain, so I decided to write a couple Python functions to help with this.

For example:

>>> eax = 0x4004121  # Taken from a register after executing a CPUID instruction with leaf-4 indicated
>>> parse_out_bits(eax, 5, 7)  # Return the value at bits 5 to 7 (inclusive)
1  # This is an L1 cache


Indices are 0-based and inclusive.

Where eax is the following, and I want the value of the bits from S to E:

                        E S
100 0000 0000 0100 0001 0010 0001‬


I'd like notes on anything here, but specifically how this could be done better in terms of bit manipulation.

from typing import Generator

def bit_place_values(start_index: int, end_index: int) -> Generator[int, None, None]:
acc = 1 << start_index
for _ in range(start_index, end_index + 1):
yield acc
acc <<= 1

def parse_out_bits(bit_field: int, start_index: int, end_index: int) -> int:
mask = sum(bit_place_values(start_index, end_index))
return (mask & bit_field) >> start_index


This is not the kind of thing you should loop for. Just calculate a mask:

def parse_out_bits(bit_field: int, start_index: int, end_index: int) -> int:
mask = (1 << (end_index - start_index + 1)) - 1
return (bit_field >> start_index) & mask


In English:

• If you're getting bits 5-7, that's 3 bits
• 2^3 == 8, - 1 = 7 (or 111 in binary - that is your mask)
• Shift the field right by 5 to put the bits of interest in the least-significant position
• And-mask them to get the result.
• Nice. But gosh, bit arithmetic is hard for me to read. (you've got it quite nice tho) – Peilonrayz Jun 3 '20 at 0:23