1# Copyright (c) 2015-2022 Intel Corporation.
2#
3# Redistribution and use in source and binary forms, with or without
4# modification, are permitted provided that the following conditions are met:
5#
6#     * Redistributions of source code must retain the above copyright notice,
7#       this list of conditions and the following disclaimer.
8#     * Redistributions in binary form must reproduce the above copyright notice,
9#       this list of conditions and the following disclaimer in the documentation
10#       and/or other materials provided with the distribution.
11#     * Neither the name of Intel Corporation nor the names of its contributors
12#       may be used to endorse or promote products derived from this software
13#       without specific prior written permission.
14#
15# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
19# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
22# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
26"""Helper functions to work with bitfields.
27
28Documentation frequently writes bitfields as the inclusive range [msb:lsb];
29this module provides functions to work with bitfields using msb and lsb rather
30than manually computing shifts and masks from those."""
31
32def bitfield_max(msb, lsb=None):
33    """Return the largest value that fits in the bitfield [msb:lsb] (or [msb] if lsb is None)"""
34    if lsb is None:
35        lsb = msb
36    return (1 << (msb - lsb + 1)) - 1
37
38def bitmask(msb, lsb=None):
39    """Creates a mask with bits [msb:lsb] (or [msb] if lsb is None) set."""
40    if lsb is None:
41        lsb = msb
42    return bitfield_max(msb, lsb) << lsb
43
44def bitfield(value, msb, lsb=None):
45    """Shift value to fit in the bitfield [msb:lsb] (or [msb] if lsb is None).
46
47    Raise OverflowError if value does not fit in that bitfield."""
48    if lsb is None:
49        lsb = msb
50    if value > bitfield_max(msb, lsb):
51        if msb == lsb:
52            field = "[{0}]".format(msb)
53        else:
54            field = "[{0}:{1}]".format(msb, lsb)
55        raise OverflowError("Value {value:#x} too big for bitfield {field}".format(**locals()))
56    return value << lsb
57
58def getbits(value, msb, lsb=None):
59    """From the specified value, extract the bitfield [msb:lsb] (or [msb] if lsb is None)"""
60    if lsb is None:
61        lsb = msb
62    return (value >> lsb) & bitfield_max(msb, lsb)
63
64def setbits(value, fieldvalue, msb, lsb=None):
65    """In the specified value, set the bitfield [msb:lsb] (or [msb] if lsb is None) to fieldvalue"""
66    value &= ~bitmask(msb, lsb)
67    value |= bitfield(fieldvalue, msb, lsb)
68    return value
69