diff options
| author | s-ol <s-ol@users.noreply.github.com> | 2020-05-29 11:50:25 +0000 |
|---|---|---|
| committer | s-ol <s-ol@users.noreply.github.com> | 2020-05-29 11:50:25 +0000 |
| commit | 517f3e141c3e3bede4e7b0c0ea7237544f28ce90 (patch) | |
| tree | d8e12207c006bc5e03a0fea3ddbab261ac09e6c7 /bits.py | |
| parent | new label-slice syntax in format.py; switch to doctest (diff) | |
| download | subv-517f3e141c3e3bede4e7b0c0ea7237544f28ce90.tar.gz subv-517f3e141c3e3bede4e7b0c0ea7237544f28ce90.zip | |
switch bit.py, subv.py to doctest
Diffstat (limited to 'bits.py')
| -rw-r--r-- | bits.py | 156 |
1 files changed, 99 insertions, 57 deletions
@@ -1,80 +1,122 @@ def u(num, bits): + """ parse an unsigned integer into a bitfield. + + >>> u(0x08, 8) + (8, 8) + >>> u(0xff, 8) + (255, 8) + + >>> u(0xf0, 7) + Traceback (most recent call last): + ... + ValueError: value 240 (u8) too large for u7 field + >>> u(-1, 8) + Traceback (most recent call last): + ... + ValueError: negative value not allowed: -1 + """ if num < 0: raise ValueError("negative value not allowed: {}".format(num)) if num.bit_length() > bits: - raise ValueError("value too large for u{} field: {} ({} bits)", - bits, num, num.bit_length()) + raise ValueError("value {} (u{}) too large for u{} field" + .format(num, num.bit_length(), bits)) return (num, bits) def i(num, bits): - if num < 0: - num = (1 << bits) + num + """ parse a signed integer into a bitfield. + + >>> i(8, 8) + (8, 8) + >>> i(-4, 8) + (252, 8) + >>> i(127, 8) + (127, 8) + >>> i(-128, 8) + (128, 8) + + >>> i(128, 8) + Traceback (most recent call last): + ... + ValueError: value 128 (i9) too large for i8 field [-128;127] + >>> i(-129, 8) + Traceback (most recent call last): + ... + ValueError: value -129 (i9) too large for i8 field [-128;127] + """ + min = -(1 << (bits - 1)) + max = -1 - min + + if num > max or num < min: + raise ValueError("value {} (i{}) too large for i{} field [{};{}]" + .format(num, num.bit_length()+1, bits, min, max)) + + if num < 0: + num = (1 << bits) + num - return u(num, bits) + return u(num, bits) def from_part(part): - val, size = part - return (val, int(size)) + """ parse a size-tagged subv part into a bit. + + >>> from_part((34, 2)) + (34, 2) + >>> from_part((34, 2, 'extra')) + (34, 2) + """ + val = int(part[0]) + size = part[1] + return (val, int(size)) def concat(*parts): + """ concatenate multiple bitfields. + + >>> concat((0b10, 2), (0b00, 2)) + (2, 4) + >>> concat((0b1, 1), (0b0110, 4), (0b110, 3)) + (205, 8) + """ val, size = 0, 0 for (pval, psize) in parts: val = val | pval << size size += psize return (val, size) -def slice(bits, top, bottom): +def slice(bits, hi, lo): + """ slice a bitfield given hi and lo bit indices. + + >>> slice((0x7f, 8), 7, 4) + (7, 4) + >>> slice((0b100, 3), 2, 2) + (1, 1) + >>> slice((0x12345678, 32), 7, 0) + (120, 8) + >>> slice((0x12345678, 32), 15, 8) + (86, 8) + >>> slice((0x12345678, 32), 23, 16) + (52, 8) + + >>> slice((0xf, 4), 4, 0) + Traceback (most recent call last): + ... + ValueError: slice [4:0] out of range (4 bit value) + >>> slice((0xf, 4), 2, 3) + Traceback (most recent call last): + ... + ValueError: cant slice reverse range + >>> slice((0xf, 4), 3, -1) + Traceback (most recent call last): + ... + ValueError: slice [3:-1] out of range (4 bit value) + """ (val, size) = bits - if top < bottom: + if hi < lo: raise ValueError("cant slice reverse range") - elif bottom < 0: - raise ValueError("negative slice index") - elif top >= size: - raise ValueError("cant slice [{}:{}] from {} bit value".format(top, bottom, size)) - - width = top - bottom + 1 - val = (val >> bottom) & ((1 << width) - 1) - return (val, width) - -import unittest -class TestHelpers(unittest.TestCase): - def test_concat(self): - self.assertEqual( - concat((0b10, 2), (0b00, 2)), - (0b0010, 4) - ) - self.assertEqual( - concat((0b1, 1), (0b0110, 4), (0b110, 3)), - (0b11001101, 8) - ) - - def test_slice(self): - self.assertEqual( - slice((0x7f, 8), 7, 4), - (0x7, 4) - ) - self.assertEqual( - slice((0b100, 3), 2, 2), - (0b1, 1) - ) - with self.assertRaises(ValueError): - slice((0xf, 4), 4, 0) - with self.assertRaises(ValueError): - slice((0xf, 4), 2, 3) - with self.assertRaises(ValueError): - slice((0xf, 4), 3, -1) - self.assertEqual( - slice((0x12345678, 32), 7, 0), - (0x78, 8) - ) - self.assertEqual( - slice((0x12345678, 32), 15, 8), - (0x56, 8) - ) - self.assertEqual( - slice((0x12345678, 32), 23, 16), - (0x34, 8) - ) + elif lo < 0 or hi >= size: + raise ValueError("slice [{}:{}] out of range ({} bit value)".format(hi, lo, size)) + + size = hi - lo + 1 + val = (val >> lo) & ((1 << size) - 1) + return (val, size) |
