Numeric Tools
Hardware Related Numeric Calculations.
Classes:
| Name | Description |
|---|---|
AlignError |
Alignment Error. |
Functions:
| Name | Description |
|---|---|
unsigned_to_hex |
Convert unsigned |
signed_to_hex |
Convert signed |
signed_to_unsigned |
Convert signed |
unsigned_to_signed |
Convert unsigned |
calc_unsigned_width |
Return width in bits for |
calc_signed_width |
Return width in bits for |
calc_lowest_bit_set |
Return bit number which is not zero. |
is_power_of2 |
Return |
is_power_of |
Return |
calc_next_power_of2 |
Return next power of 2. |
calc_next_power_of |
Return next power of |
calc_prev_power_of2 |
Return previous power of |
calc_prev_power_of |
Return previous power of |
align |
Forward |
bytes2words |
Convert list of bytes to list of words. |
bytes2word |
Convert list of bytes to one word. |
words2bytes |
Convert list of words to list of bytes. |
convwidth |
Convert iterable with values of |
to_mask |
Convert address range starting at |
calc_addrwinmasks |
Return tuple of binary compare wildcard masks for address window of |
split_aligned_segs |
Split address window starting at |
AlignError
Bases: RuntimeError
Alignment Error.
unsigned_to_hex
Convert unsigned value to width bit hex.
Example:
>>> unsigned_to_hex(166, 8)
'A6'
>>> unsigned_to_hex(3, 6)
'03'
>>> unsigned_to_hex(5, 9)
'005'
>>> unsigned_to_hex(26000000, 32)
'018CBA80'
>>> unsigned_to_hex(16, 4)
Traceback (most recent call last):
...
ValueError: 16 is not a unsigned 4 bit integer
>>> unsigned_to_hex(-1, 4)
Traceback (most recent call last):
...
ValueError: -1 is not a unsigned 4 bit integer
>>> unsigned_to_hex(26000000, 32, prefix="{width}'h")
"32'h018CBA80"
>>> unsigned_to_hex(248, 8, prefix="0x")
'0xF8'
signed_to_hex
Convert signed value to width bit hex.
Example:
>>> signed_to_hex(15, 8)
'0F'
>>> signed_to_hex(-3, 6)
'3D'
>>> signed_to_hex(5, 9)
'005'
>>> signed_to_hex(-9, 4)
Traceback (most recent call last):
...
ValueError: -9 is not a signed 4 bit integer
>>> signed_to_hex(8, 4)
Traceback (most recent call last):
...
ValueError: 8 is not a signed 4 bit integer
>>> signed_to_hex(5, 9, prefix="{width}'h")
"9'h005"
signed_to_unsigned
Convert signed value to unsigned with width.
Example:
>>> signed_to_unsigned(3, 4)
3
>>> signed_to_unsigned(-3, 4)
13
>>> signed_to_unsigned(-3, 8)
253
>>> signed_to_unsigned(-9, 4)
Traceback (most recent call last):
...
ValueError: -9 is not a signed 4 bit integer
>>> signed_to_unsigned(8, 4)
Traceback (most recent call last):
...
ValueError: 8 is not a signed 4 bit integer
unsigned_to_signed
Convert unsigned value to signed with width.
Example:
>>> unsigned_to_signed(3, 4)
3
>>> unsigned_to_signed(13, 4)
-3
>>> unsigned_to_signed(253, 8)
-3
>>> unsigned_to_signed(-9, 4)
Traceback (most recent call last):
...
ValueError: -9 is not a unsigned 4 bit integer
calc_unsigned_width
Return width in bits for value.
>>> calc_unsigned_width(3)
2
>>> calc_unsigned_width(4)
3
>>> calc_unsigned_width(7)
3
>>> calc_unsigned_width(8)
4
>>> calc_unsigned_width(15)
4
>>> calc_unsigned_width(16)
5
>>> calc_unsigned_width(8191)
13
>>> calc_unsigned_width(0)
1
>>> calc_unsigned_width(-5)
Traceback (most recent call last):
...
AssertionError: Value must be not negative. -5 is not.
calc_signed_width
Return width in bits for value.
>>> calc_signed_width(15)
5
>>> calc_signed_width(16)
6
>>> calc_signed_width(8191)
14
>>> calc_signed_width(-7)
4
>>> calc_signed_width(-8)
4
>>> calc_signed_width(-9)
5
>>> calc_signed_width(0)
1
calc_lowest_bit_set
Return bit number which is not zero.
Example:
>>> calc_lowest_bit_set(0xE0)
5
>>> calc_lowest_bit_set(-8)
3
>>> calc_lowest_bit_set(0)
is_power_of2
Return True if value is power of 2.
>>> is_power_of2(15)
False
>>> is_power_of2(16)
True
>>> is_power_of2(17)
False
>>> is_power_of2(-5)
Traceback (most recent call last):
...
AssertionError: Value must be larger than zero. -5 is not.
>>> is_power_of2(0)
False
is_power_of
Return True if value is power of base.
>>> is_power_of(15)
False
>>> is_power_of(16)
True
>>> is_power_of(17)
False
>>> is_power_of(-5)
Traceback (most recent call last):
...
AssertionError: Value must be larger than zero. -5 is not.
>>> is_power_of(8, base=3)
False
>>> is_power_of(9, base=3)
True
>>> is_power_of(-9, base=3)
Traceback (most recent call last):
...
AssertionError: Value must be larger than zero. -9 is not.
>>> is_power_of(0)
False
>>> is_power_of(0, base=6)
False
calc_next_power_of2
Return next power of 2.
The returned value fulfills the rule 2**ceil(log2(value)) >= value.
>>> calc_next_power_of2(1)
2
>>> calc_next_power_of2(10)
16
>>> calc_next_power_of2(16)
16
>>> calc_next_power_of2(17)
32
>>> calc_next_power_of2(-5)
Traceback (most recent call last):
...
AssertionError: Value must be positive. -5 is not.
calc_next_power_of
Return next power of base.
The returned value fulfills the rule base**ceil(log_base(value)) >= value.
>>> calc_next_power_of(1)
2
>>> calc_next_power_of(1, base=5)
5
>>> calc_next_power_of(10)
16
>>> calc_next_power_of(10, base=3)
27
>>> calc_next_power_of(16)
16
>>> calc_next_power_of(9, base=3)
9
>>> calc_next_power_of(17)
32
>>> calc_next_power_of(-5)
Traceback (most recent call last):
...
AssertionError: Value must be positive. -5 is not.
calc_prev_power_of2
Return previous power of base.
The returned value fulfills the rule 2**floor(log2(value)) <= value.
>>> calc_prev_power_of2(1)
1
>>> calc_prev_power_of2(15)
8
>>> calc_prev_power_of2(16)
16
>>> calc_prev_power_of2(17)
16
>>> calc_prev_power_of2(-5)
Traceback (most recent call last):
...
AssertionError: Value must be positive. -5 is not.
calc_prev_power_of
Return previous power of base.
The returned value fulfills the rule base**exp <= value.
>>> calc_prev_power_of(1)
1
>>> calc_prev_power_of(1, base=7)
1
>>> calc_prev_power_of(15)
8
>>> calc_prev_power_of(16)
16
>>> calc_prev_power_of(17)
16
>>> calc_prev_power_of(10, base=3)
9
>>> calc_prev_power_of(27, base=3)
27
>>> calc_prev_power_of(-5)
Traceback (most recent call last):
...
AssertionError: Value must be positive. -5 is not.
align
Forward value to offset and align and minalign.
Without offset and align nothing happens.
>>> align(5)
5
>>> align(7)
7
An offset forwards the count if necessary or raises an :any:AlignError.
>>> align(5, offset=8)
8
>>> align(5, offset=3)
Traceback (most recent call last):
...
icdutil.num.AlignError: Cannot use offset 3 as we are already at 5
A align forwards the value to the next multiple of align.
>>> align(5, align=4)
8
>>> align(8, align=4)
8
>>> align(9, align=4)
12
A minalign without align forwards the value to the next multiple of minalign
>>> align(5, minalign=4)
8
>>> align(8, minalign=4)
8
>>> align(9, minalign=4)
12
If both align and minalign are given, then the value is moved to the next multiple
of whichever of the both align values is bigger
>>> align(8, align=5, minalign=4)
10
>>> align(8, align=4, minalign=6)
12
If offset is given it is dominant over both align and minalign
>>> align(8, offset=9, align=4, minalign=6)
9
bytes2words
Convert list of bytes to list of words.
>>> for word in bytes2words([0x11, 0x22, 0x33, 0x44, 0x55, 0x66]):
... print("0x%X" % word)
0x44332211
0x6655
>>> for word in bytes2words(bytes.fromhex("112233445566")):
... print("0x%X" % word)
0x44332211
0x6655
>>> for word in bytes2words([0x11, 0x22, 0x33, 0x44, 0x55, 0x66], bytesperword=2):
... print("0x%X" % word)
0x2211
0x4433
0x6655
>>> for word in bytes2words([]):
... print("0x%X" % word)
bytes2word
Convert list of bytes to one word.
>>> print("0x%X" % bytes2word([0x11, 0x22, 0x33, 0x44, 0x55, 0x66]))
0x665544332211
words2bytes
Convert list of words to list of bytes.
>>> for byte_ in words2bytes([0x44332211, 0x6655]):
... print("0x%X" % byte_)
0x11
0x22
0x33
0x44
0x55
0x66
0x0
0x0
>>> for byte_ in words2bytes([0x44332211, 0x6655], bytesperword=6):
... print("0x%X" % byte_)
0x11
0x22
0x33
0x44
0x0
0x0
0x55
0x66
0x0
0x0
0x0
0x0
convwidth
Convert iterable with values of srcwidth to list of values of destwidth.
>>> [hex(i) for i in convwidth([0x04030201, 0x08070605], 32, 16)]
['0x201', '0x403', '0x605', '0x807']
>>> [hex(i) for i in convwidth([0x0807060504030201], 64, 16)]
['0x201', '0x403', '0x605', '0x807']
>>> [hex(i) for i in convwidth([0x0807060504030201], 64, 8)]
['0x1', '0x2', '0x3', '0x4', '0x5', '0x6', '0x7', '0x8']
>>> [hex(i) for i in convwidth([], 32, 16)]
[]
>>> [hex(i) for i in convwidth([0x201, 0x403, 0x605, 0x807], 16, 32)]
['0x4030201', '0x8070605']
>>> [hex(i) for i in convwidth([0x201, 0x403, 0x605, 0x807], 16, 64)]
['0x807060504030201']
>>> [hex(i) for i in convwidth([0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8], 8, 64)]
['0x807060504030201']
>>> [hex(i) for i in convwidth([0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8], 8, 56)]
['0x7060504030201', '0x8']
>>> [hex(i) for i in convwidth([], 16, 32)]
[]
>>> [hex(i) for i in convwidth([0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8], 8, 8)]
['0x1', '0x2', '0x3', '0x4', '0x5', '0x6', '0x7', '0x8']
to_mask
Convert address range starting at baseaddr with 2**exp elements to mask.
>>> to_mask(16, 0x4000, 6)
'0100000000??????'
>>> to_mask(16, 0x6000, 4, 'x')
'011000000000xxxx'
>>> to_mask(16, 0x4004, 6)
Traceback (most recent call last):
...
AssertionError: 6 LSBs of '0100000000000100' shall be '000000', not '000100'
calc_addrwinmasks
Return tuple of binary compare wildcard masks for address window of size starting at baseaddr.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
baseaddr
|
int
|
Address window start address |
required |
size
|
int
|
Address window size |
required |
Other Parameters:
| Name | Type | Description |
|---|---|---|
addrwidth |
int
|
Address width in bits |
dontcare |
str
|
Character used for don't care bits |
Example:
>>> calc_addrwinmasks(0, 1, addrwidth=4)
('0000',)
>>> calc_addrwinmasks(0xF000, 0x10, addrwidth=16)
('111100000000????',)
>>> calc_addrwinmasks(0xF000, 0x180, addrwidth=16, dontcare='x')
('11110000xxxxxxxx', '111100010xxxxxxx')
>>> calc_addrwinmasks(0xEFF0, 0x100, addrwidth=16)
('111011111111????', '111100000???????', '1111000010??????', '11110000110?????', '111100001110????')
split_aligned_segs
Split address window starting at baseaddr with size into segments with aligned base addresses.
The base addresses of the segments are aligned to calc_next_power_of2(size).
Returns tuple of :any:AddrRange. Segment starting at baseaddr with size.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
baseaddr
|
int
|
Address window start address |
required |
size
|
int
|
Address window size |
required |
Example:
>>> split_aligned_segs(0, 1)
(AddrRange(0x0, '1 byte'),)
>>> split_aligned_segs(1024, 16)
(AddrRange(0x400, '16 bytes'),)
>>> split_aligned_segs(1024, 1024)
(AddrRange(0x400, '1 KB'),)
>>> split_aligned_segs(1024, 1024+768)
(AddrRange(0x400, '1 KB'), AddrRange(0x800, '768 bytes'))
>>> split_aligned_segs(256, 1024+768)
(AddrRange(0x100, '256 bytes'), AddrRange(0x200, '512 bytes'), AddrRange(0x400, '1 KB'))
>>> split_aligned_segs(1000, 1024) # doctest: +ELLIPSIS
(AddrRange(0x3E8, '8 bytes'), AddrRange(0x3F0, '16 bytes'), AddrRange(0x400, '512 b...(0x600, '488 bytes'))