Bit Slicing

Sometimes you want to access only certain bits of a FixedPoint number. The FixedPoint.bits attribute returns a FixedPointBits object, which is an int that support square bracket access.

Bit Random Access

One or more contiguous bits in the FixedPointBits can be accessed with an int or slice key.

Single-Bit Random Access

To access a single bit use an integer key. Bits are indexed with the MSb being index m+n-1 and the LSb being index 0.

>>> x = FixedPoint('0b001001', signed=0, m=3, n=3, str_base=2)
>>> bin(x.bits), x.bits[3]
('0b1001', 1)

You can also access a single bit using a slice when start and stop values are equal. The slice step must be either

  • -1 (indicating a descending range with the MSb as index m+n-1 and the LSb as index 0)

  • +1 (indicating an ascending range with the MSb as index 0 and the LSb as index m+n-1)

>>> x = FixedPoint('0b001000', signed=0, m=3, n=3)
>>> x.bits[3:3:-1] # the middle '1' with a descending range
1
>>> x.bits[2:2:1] # the middle '1' with an ascending range
1

Attempting to access a single bit in this fashion (the slice start and stop are equal) without specifying a step results in an error.

>>> x.bits[3:3]
Traceback (most recent call last):
    ...
IndexError: Step must be 1 or -1 for equivalent start and stop bound 3.

Multi-Bit Random Access

To access multiple bits at a time, slices are employed. Both ascending and descending ranges are supported.

>>> x = FixedPoint(0b0001100, m=7)
>>> x.bits[3:2] # Access the middle two 1s using a descending range
3
>>> x.bits[3:2:-1] # The step can be -1 for clarity but is unnecessary
3
>>> x.bits[3:4] # Access the middle two 1s using an ascending range
3
>>> x.bits[3:4:1] # The step can be +1 for clarity but is unnecessary
3

When a step is used that is not 1 or -1, or when the start/stop index is negative, the slice accesses the bits as if they were a str.

>>> x = FixedPoint(0b100_100_100_100)
>>> x.bits[::3] # Get every 3rd bit starting from the first
15
>>> bin(x.bits[:-6]) # Get the last 6 bits
'0b100100'

Bit Mappings

Common parts of the FixedPoint bit string are mapped to keys, specified as strings (like a dict).

These include:

  • integer bits ('m' or 'int')

  • fractional bits ('n' or 'frac')

  • sign bit ('s' or 'sign')

  • most significant bit ('msb')

  • least significant bit ('lsb')

If the portion of the FixedPoint bits does not exist (e.g., the sign bit of an unsigned number), a KeyError is raised.

>>> intonly = signed = FixedPoint("0b1110", 1, 4, 0)
>>> fraconly = unsigned = FixedPoint("0b0001", 0, 0, 4)
>>> intonly.bits['m']
14
>>> fraconly.bits['int']
Traceback (most recent call last):
    ...
KeyError: "Invalid bit specification 'int' for UQ0.4 format."

>>> intonly.bits['n']
Traceback (most recent call last):
    ...
KeyError: "Invalid bit specification 'n' for Q4.0 format."
>>> signed.bits['sign']
1
>>> (-signed).bits['s']
0
>>> unsigned.bits['sign']
Traceback (most recent call last):
    ...
KeyError: "Invalid bit specification 'sign' for UQ0.4 format."

>>> intonly.bits['msb'], intonly.bits['lsb']
(1, 0)
>>> fraconly.bits['msb'], fraconly.bits['lsb']
(0, 1)

When the mappings are uppercased, a str type is returned corresponding to the binary bits.

>>> intonly = signed = FixedPoint("0b1110", 1, 4, 0)
>>> fraconly = unsigned = FixedPoint("0b0001", 0, 0, 4)
>>> intonly.bits['M']
'1110'
>>> fraconly.bits['INT']
Traceback (most recent call last):
    ...
KeyError: "Invalid bit specification 'INT' for UQ0.4 format."

>>> intonly.bits['N']
Traceback (most recent call last):
    ...
KeyError: "Invalid bit specification 'N' for Q4.0 format."
>>> signed.bits['SIGN']
'1'
>>> (-signed).bits['S']
'0'
>>> unsigned.bits['SIGN']
Traceback (most recent call last):
    ...
KeyError: "Invalid bit specification 'SIGN' for UQ0.4 format."

>>> intonly.bits['MSB'], intonly.bits['LSB']
('1', '0')
>>> fraconly.bits['MSB'], fraconly.bits['LSB']
('0', '1')