icdutil.addrmap module

Address Map.

class icdutil.addrmap.AddrMap(addrwidth: Optional[int] = None, is_sub: bool = False, allow_overlapping: bool = False, AddrMap__addrranges: list = _Nothing.NOTHING)[source]

Bases: object

Address Map.

Keyword Arguments:
  • addrwidth (int) – Address width. Calculated automatically.

  • is_sub (bool) – Handle sub addresses only. Just the minimum number of address bits is evaluated.

  • default (#) – Default item, returned on unallocated address ranges.

  • allow_overlapping (bool) – Allow overlapping address ranges.

>>> a = AddrMap()
>>> a
AddrMap()
>>> a.add('T', size=0x400)
AddrRange('T', 0x0, '1 KB')
>>> a.add('A', 0x5000, 0x1000)
AddrRange('A', 0x5000, '4 KB')
>>> a.add('B', 0x2000, 0x1000)
AddrRange('B', 0x2000, '4 KB')
>>> a.add('C', 0xD000, 0x800)
AddrRange('C', 0xD000, '2 KB')
>>> a.add('Z', size=0x1000)
AddrRange('Z', 0xE000, '4 KB')
>>> a.add('X', 0xF0800000, 1024*1024*3)
AddrRange('X', 0xF0800000, '3 MB')

Addresses can be used only once:

>>> a.add('D', 0xE400, 0x0400)
Traceback (most recent call last):
    ...
icdutil.addrmap.Conflict: AddrRange('D', 0xE400, '1 KB'): overlaps with AddrRange('Z', 0xE000, '4 KB').
>>> a.add('D', 0x2000)
Traceback (most recent call last):
    ...
icdutil.addrmap.Conflict: AddrRange('D', 0x2000, '1 byte'): overlaps with AddrRange('B', 0x2000, '4 KB').
>>> a.add('D', 0x2000, '8 KB')
Traceback (most recent call last):
    ...
icdutil.addrmap.Conflict: AddrRange('D', 0x2000, '8 KB'): overlaps with AddrRange('B', 0x2000, '4 KB').
>>> a.add('D', 0x1800, '4 KB')
Traceback (most recent call last):
    ...
icdutil.addrmap.Conflict: AddrRange('D', 0x1800, '4 KB'): overlaps with AddrRange('B', 0x2000, '4 KB').

An iteration will serve AddrRange objects sorted by baseaddr:

>>> for addrrange in a:
...     addrrange
AddrRange('T', 0x0, '1 KB')
AddrRange('B', 0x2000, '4 KB')
AddrRange('A', 0x5000, '4 KB')
AddrRange('C', 0xD000, '2 KB')
AddrRange('Z', 0xE000, '4 KB')
AddrRange('X', 0xF0800000, '3 MB')

The size is defined by the numer of entries:

>>> len(a)
6

By using a default the gaps are filled with this item:

>>> for addrrange in a.get(default='d'):
...     addrrange
AddrRange('T', 0x0, '1 KB')
AddrRange('d', 0x400, '7 KB')
AddrRange('B', 0x2000, '4 KB')
AddrRange('d', 0x3000, '8 KB')
AddrRange('A', 0x5000, '4 KB')
AddrRange('d', 0x6000, '28 KB')
AddrRange('C', 0xD000, '2 KB')
AddrRange('d', 0xD800, '2 KB')
AddrRange('Z', 0xE000, '4 KB')
AddrRange('d', 0xF000, '3.76 GB')
AddrRange('X', 0xF0800000, '3 MB')
AddrRange('d', 0xF0B00000, '245 MB')
>>> len(tuple(a.get('d')))
12

The is_sub attribute defines the address range defaults:

>>> b = AddrMap(addrwidth=32, is_sub=True)
>>> b
AddrMap(addrwidth=32, is_sub=True)
>>> b.add('T', size=0x400)
AddrRange('T', 0x00000000, '1 KB', addrwidth=32, is_sub=True)
>>> b.add('A', 0x5000, 0x1000)
AddrRange('A', 0x00005000, '4 KB', addrwidth=32, is_sub=True)
>>> b.add('B', 0x2000, 0x1000)
AddrRange('B', 0x00002000, '4 KB', addrwidth=32, is_sub=True)
>>> b.add('C', 0xD000, 0x800)
AddrRange('C', 0x0000D000, '2 KB', addrwidth=32, is_sub=True)
>>> b.add('Z', size=0x1000)
AddrRange('Z', 0x0000E000, '4 KB', addrwidth=32, is_sub=True)
>>> b.add('X', 0xF0800000, 1024*1024*3, is_sub=False)
AddrRange('X', 0xF0800000, '3 MB', addrwidth=32)
>>> for addrrange in b:
...     addrrange
AddrRange('T', 0x00000000, '1 KB', addrwidth=32, is_sub=True)
AddrRange('B', 0x00002000, '4 KB', addrwidth=32, is_sub=True)
AddrRange('A', 0x00005000, '4 KB', addrwidth=32, is_sub=True)
AddrRange('C', 0x0000D000, '2 KB', addrwidth=32, is_sub=True)
AddrRange('Z', 0x0000E000, '4 KB', addrwidth=32, is_sub=True)
AddrRange('X', 0xF0800000, '3 MB', addrwidth=32)

The allow_overlapping attibute allows address ranges to intersect.

>>> c = AddrMap(allow_overlapping=True)
>>> c
AddrMap(allow_overlapping=True)
>>> c.add('L', size=0x1000)
AddrRange('L', 0x0, '4 KB')
>>> c.add('R', 0x400, size=0x1000)
AddrRange('R', 0x400, '4 KB')
>>> c.add('M', 0x200, '2 KB')
AddrRange('M', 0x200, '2 KB')
>>> for addrrange in c:
...     addrrange
AddrRange('L', 0x0, '4 KB')
AddrRange('M', 0x200, '2 KB')
AddrRange('R', 0x400, '4 KB')
add(item, baseaddr: Optional[int] = None, size: int = 1, is_sub: Optional[bool] = None, align: Optional[int] = None, startsearch: Optional[int] = None) AddrRange[source]

Add item for address decoding.

Parameters:

item – any object managed by this address decoder

Keyword Arguments:
  • baseaddr – Base address. Behind last item by default.

  • size – Size in bytes

  • is_sub – Overwrite sub address attribute.

  • align – Alignment

  • startsearch – Search of free address at given number (if baseaddr is None)

>>> a = AddrMap()
>>> a.add('A', baseaddr=0x3000, size='4 KB')
AddrRange('A', 0x3000, '4 KB')
>>> a.add('B', 0x1000, '1 KB', is_sub=True)
AddrRange('B', 0x1000, '1 KB', is_sub=True)
>>> a.add('C', 0x4500, '4 KB', align=0x1000)
AddrRange('C', 0x5000, '4 KB')
property addrspace: Optional[int]

Allocated Address space.

>>> a = AddrMap()
>>> a.addrspace
>>> a.add('A', 0x5000, '4 KB')
AddrRange('A', 0x5000, '4 KB')
>>> str(a.addrspace)
'0x1000'
>>> a.add('B', 0x2000, '4 KB')
AddrRange('B', 0x2000, '4 KB')
>>> str(a.addrspace)
'0x4000'
>>> a.add('C', 0x7000, 13)
AddrRange('C', 0x7000, '13 bytes')
>>> str(a.addrspace)
'0x500D'
addrwidth: Optional[int]
allow_overlapping: bool
cp_addrranges(addranges: List[AddrRange]) None[source]

Copy address ranges from other AddrMap.

cut(baseaddr, size=1) AddrMap[source]

Cut out address range from baseaddr for size.

Return address map with cut address ranges.

>>> a = AddrMap()
>>> a.add('A', 0x0000, 0x1000)
AddrRange('A', 0x0, '4 KB')
>>> a.add('B', 0x1000, 0x1000)
AddrRange('B', 0x1000, '4 KB')
>>> a.add('C', 0x2000, 0x1000)
AddrRange('C', 0x2000, '4 KB')
>>> a.add('D', 0x3000, 0x1000)
AddrRange('D', 0x3000, '4 KB')
>>> print(a.get_overview())
Baseaddr    Size           Sub    Item
----------  -------------  -----  ------
0x0         0x1000 (4 KB)  No     'A'
0x1000      0x1000 (4 KB)  No     'B'
0x2000      0x1000 (4 KB)  No     'C'
0x3000      0x1000 (4 KB)  No     'D'

Cut multiple address ranges

>>> c = a.cut(0x1800, 0x1000)
>>> print(a.get_overview())
Baseaddr    Size           Sub    Item
----------  -------------  -----  ------
0x0         0x1000 (4 KB)  No     'A'
0x1000      0x800 (2 KB)   No     'B'
0x2800      0x800 (2 KB)   No     'C'
0x3000      0x1000 (4 KB)  No     'D'
>>> print(c.get_overview())
Baseaddr    Size          Sub    Item
----------  ------------  -----  ------
0x1800      0x800 (2 KB)  No     'B'
0x2000      0x800 (2 KB)  No     'C'

Cut at the front

>>> c = a.cut(0, 0x1000)
>>> print(a.get_overview())
Baseaddr    Size           Sub    Item
----------  -------------  -----  ------
0x1000      0x800 (2 KB)   No     'B'
0x2800      0x800 (2 KB)   No     'C'
0x3000      0x1000 (4 KB)  No     'D'
>>> print(c.get_overview())
Baseaddr    Size           Sub    Item
----------  -------------  -----  ------
0x0         0x1000 (4 KB)  No     'A'

Cut at the end

>>> c = a.cut(0x3C00, 0x1000)
>>> print(a.get_overview())
Baseaddr    Size          Sub    Item
----------  ------------  -----  ------
0x1000      0x800 (2 KB)  No     'B'
0x2800      0x800 (2 KB)  No     'C'
0x3000      0xC00 (3 KB)  No     'D'
>>> print(c.get_overview())
Baseaddr    Size          Sub    Item
----------  ------------  -----  ------
0x3C00      0x400 (1 KB)  No     'D'

Cut exactly one

>>> c = a.cut(0x2800, '2 KB')
>>> print(a.get_overview())
Baseaddr    Size          Sub    Item
----------  ------------  -----  ------
0x1000      0x800 (2 KB)  No     'B'
0x3000      0xC00 (3 KB)  No     'D'
>>> print(c.get_overview())
Baseaddr    Size          Sub    Item
----------  ------------  -----  ------
0x2800      0x800 (2 KB)  No     'C'

Cut nothing

>>> c = a.cut(0x2000, 0x100)
>>> print(a.get_overview())
Baseaddr    Size          Sub    Item
----------  ------------  -----  ------
0x1000      0x800 (2 KB)  No     'B'
0x3000      0xC00 (3 KB)  No     'D'
>>> print(c.get_overview())
Baseaddr    Size      Sub    Item
----------  --------  -----  ------
property decode_lsb: Optional[int]

Address decoding LSB (counted from 0).

>>> a = AddrMap()
>>> a.decode_lsb is None
True
>>> a.add('A', 0x2000, '8 KB')
AddrRange('A', 0x2000, '8 KB')
>>> a.decode_lsb
13
>>> a.add('B', 0x5000, '1 KB')
AddrRange('B', 0x5000, '1 KB')
>>> a.decode_lsb
10
>>> a.add('C', 0x6000, '2 KB')
AddrRange('C', 0x6000, '2 KB')
>>> a.decode_lsb
10
property decode_msb: Optional[int]

Address decoding MSB (counted from 0).

>>> a = AddrMap(addrwidth=32)
>>> a.is_sub
False
>>> a.decode_msb
31
>>> a.add('A', 0x5000, '4 KB')
AddrRange('A', 0x00005000, '4 KB', addrwidth=32)
>>> a.decode_msb
31
>>> a = AddrMap(is_sub=True)
>>> a.is_sub
True
>>> a.decode_msb is None
True
>>> a.add('A', 0x1000, '1 KB')
AddrRange('A', 0x1000, '1 KB', is_sub=True)
>>> a.decode_msb
12
>>> a.add('B', 0x2000, '8 KB')
AddrRange('B', 0x2000, '8 KB', is_sub=True)
>>> a.decode_msb
13
>>> a.add('C', 0x4000, 1)
AddrRange('C', 0x4000, '1 byte', is_sub=True)
>>> a.decode_msb
14
property decode_slice

Address Slice.

>>> a = AddrMap()
>>> a.decode_slice is None
True
>>> a.add('A', 0x1000, '4 KB')
AddrRange('A', 0x1000, '4 KB')
>>> a.decode_slice
Slice('12')
>>> a.add('B', 0x3000, '8 KB')
AddrRange('B', 0x3000, '8 KB')
>>> a.decode_slice
Slice('14:12')
property eff_addrwidth: Optional[int]

Effective Address Width.

Return address width, either explicitly set or calculated from existing entries.

>>> a = AddrMap()
>>> a.eff_addrwidth
>>> a.add('A', 0x5000, '4 KB')
AddrRange('A', 0x5000, '4 KB')
>>> a.eff_addrwidth
15
>>> a = AddrMap(addrwidth=16)
>>> a.eff_addrwidth
16
>>> a.add('A', 2**18, '4 KB')
Traceback (most recent call last):
    ...
RuntimeError: AddrRange('A', 0x40000, '4 KB', addrwidth=16): exceeds maximum address range of 0x10000.
find(item) AddrMap[source]

Return address map with address ranges containing item.

>>> a = AddrMap()
>>> a.add('A', 0x5000, 0x1000)
AddrRange('A', 0x5000, '4 KB')
>>> a.add('B', 0x2000, 0x1000)
AddrRange('B', 0x2000, '4 KB')
>>> a.add('A', 0xD000, 0x800)
AddrRange('A', 0xD000, '2 KB')
>>> list(a.find('A'))
[AddrRange('A', 0x5000, '4 KB'), AddrRange('A', 0xD000, '2 KB')]
property firstaddr: Optional[int]

First used address.

>>> a = AddrMap()
>>> a.firstaddr
>>> a.add('A', 0x5000, '4 KB')
AddrRange('A', 0x5000, '4 KB')
>>> a.firstaddr
Hex('0x5000')
>>> a.add('B', 0x2000, '4 KB')
AddrRange('B', 0x2000, '4 KB')
>>> a.firstaddr
Hex('0x2000')
get(default=None)[source]

Return all AddrRange items and fill gaps with default.

>>> a = AddrMap()
>>> a.add('T', size=0x400)
AddrRange('T', 0x0, '1 KB')
>>> a.add('A', 0x5000, 0x1000)
AddrRange('A', 0x5000, '4 KB')
>>> a.add('B', 0x2000, 0x1000)
AddrRange('B', 0x2000, '4 KB')
>>> a.add('C', 0xD000, '2 KB')
AddrRange('C', 0xD000, '2 KB')
>>> a.add('Z', size=0x2000)
AddrRange('Z', 0xE000, '8 KB')
>>> for addrrange in a.get():
...     addrrange
AddrRange('T', 0x0, '1 KB')
AddrRange('B', 0x2000, '4 KB')
AddrRange('A', 0x5000, '4 KB')
AddrRange('C', 0xD000, '2 KB')
AddrRange('Z', 0xE000, '8 KB')
>>> for addrrange in a.get(default='reserved'):
...     addrrange
AddrRange('T', 0x0, '1 KB')
AddrRange('reserved', 0x400, '7 KB')
AddrRange('B', 0x2000, '4 KB')
AddrRange('reserved', 0x3000, '8 KB')
AddrRange('A', 0x5000, '4 KB')
AddrRange('reserved', 0x6000, '28 KB')
AddrRange('C', 0xD000, '2 KB')
AddrRange('reserved', 0xD800, '2 KB')
AddrRange('Z', 0xE000, '8 KB')

Empty:

>>> a = AddrMap()
>>> list(a.get())
[]
>>> list(a.get(default="<default>"))
[]
>>> a = AddrMap(addrwidth=16)
>>> list(a.get(default="<default>"))
[AddrRange('<default>', 0x0000, '64 KB', addrwidth=16)]

Default items before and after real AddrRange:

>>> a.add('A', 0x5000, 0x1000)
AddrRange('A', 0x5000, '4 KB', addrwidth=16)
>>> for addrrange in a.get(default='reserved'):
...     addrrange
AddrRange('reserved', 0x0000, '20 KB', addrwidth=16)
AddrRange('A', 0x5000, '4 KB', addrwidth=16)
AddrRange('reserved', 0x6000, '40 KB', addrwidth=16)
>>> a.add('Z', 0xE000, size=0x2000)
AddrRange('Z', 0xE000, '8 KB', addrwidth=16)
>>> for addrrange in a.get(default='reserved'):
...     addrrange
AddrRange('reserved', 0x0000, '20 KB', addrwidth=16)
AddrRange('A', 0x5000, '4 KB', addrwidth=16)
AddrRange('reserved', 0x6000, '32 KB', addrwidth=16)
AddrRange('Z', 0xE000, '8 KB', addrwidth=16)
get_free_baseaddr(size: int, align=None, start=None) int[source]

Return baseaddress of free window with size.

Parameters:

size – Window Size

Keyword Arguments:
  • align – Alignment, default aligned to size

  • start – Start search behind given address

>>> a = AddrMap(is_sub=True, addrwidth=16)
>>> a.get_free_baseaddr(0x10, start=0x0)
Hex('0x0')
>>> a.add('A', 0x1000, '1 KB')
AddrRange('A', 0x1000, '1 KB', addrwidth=16, is_sub=True)
>>> a.get_free_baseaddr(0x400)
Hex('0x1400')
>>> a.get_free_baseaddr('4 KB')
Hex('0x2000')
>>> a.get_free_baseaddr('8 KB', align=0x4000)
Hex('0x4000')
>>> a.get_free_baseaddr('1 KB', start=0x400)
Hex('0x400')
>>> a.get_free_baseaddr('1 KB', start=0x4000)
Hex('0x4000')
>>> a.add('B', 0x3000, '4 KB')
AddrRange('B', 0x3000, '4 KB', addrwidth=16, is_sub=True)
>>> a.get_free_baseaddr('4 KB', start=0x2800)
Hex('0x4000')

If the AddrMap has addrwidth set, a check for end range overflow is executed

>>> a.get_free_baseaddr('8 KB', start=0xF0000)
Traceback (most recent call last):
    ...
ValueError: No space left in address map (64 KB) for new range at 0xF0000 with size of 8 KB
>>> a.get_free_baseaddr('8 KB', align=0x1000, start=0xF000)
Traceback (most recent call last):
    ...
ValueError: No space left in address map (64 KB) for new range at 0xF000 with size of 8 KB
get_overview() str[source]

Return overview table.

>>> a = AddrMap()
>>> a.add('A', 0x5000, 0x1000)
AddrRange('A', 0x5000, '4 KB')
>>> a.add('B', 0x2000, 0x1000)
AddrRange('B', 0x2000, '4 KB')
>>> a.add('C', 0xD000, 0x800)
AddrRange('C', 0xD000, '2 KB')
>>> print(a.get_overview())
Baseaddr    Size           Sub    Item
----------  -------------  -----  ------
0x2000      0x1000 (4 KB)  No     'B'
0x5000      0x1000 (4 KB)  No     'A'
0xD000      0x800 (2 KB)   No     'C'
property is_full

Return if entire address map range is covered.

>>> a = AddrMap()
>>> a.is_full is None
True
>>> a.add('A', size='8 KB')
AddrRange('A', 0x0, '8 KB')
>>> a.is_full
True
>>> a.add('B', size='4 KB')
AddrRange('B', 0x2000, '4 KB')
>>> a.is_full
False
>>> a.add('C', size='4 KB')
AddrRange('C', 0x3000, '4 KB')
>>> a.is_full
True
>>> b = AddrMap(addrwidth=13)
>>> b.is_full is None
True
>>> b.add('A', 0x0, size='6 KB')
AddrRange('A', 0x0000, '6 KB', addrwidth=13)
>>> b.is_full
False
>>> b.add('B', size='2 KB')
AddrRange('B', 0x1800, '2 KB', addrwidth=13)
>>> b.is_full
True
is_sub: bool
property lastaddr: Optional[int]

Last used address.

lookup(addr: int)[source]

Lookup address range by addr.

>>> a = AddrMap()
>>> a.add('A', 0x5000, 0x1000)
AddrRange('A', 0x5000, '4 KB')
>>> a.add('B', 0x2000, 0x1000)
AddrRange('B', 0x2000, '4 KB')
>>> a.add('C', 0xD000, 0x800)
AddrRange('C', 0xD000, '2 KB')
>>> a.lookup(0x2000)
AddrRange('B', 0x2000, '4 KB')
>>> a.lookup(0x2FFF)
AddrRange('B', 0x2000, '4 KB')
>>> a.lookup(0x3000)
match(baseaddr: int, size: int = 1) AddrMap[source]

Return address map with address ranges intersecting with range from baseaddr for size.

>>> a = AddrMap()
>>> a.add('A', 0x1000, 0x1000)
AddrRange('A', 0x1000, '4 KB')
>>> a.add('B', 0x2000, 0x1000)
AddrRange('B', 0x2000, '4 KB')
>>> a.add('C', 0x3000, 0x800)
AddrRange('C', 0x3000, '2 KB')
>>> m = a.match(0x1800, 0x1000)
>>> m
AddrMap()
>>> list(m)
[AddrRange('A', 0x1000, '4 KB'), AddrRange('B', 0x2000, '4 KB')]
match_addrrange(addrrange: AddrRange) AddrMap[source]

Return address map with address ranges intersecting with range from baseaddr for size.

>>> a = AddrMap()
>>> a.add('A', 0x1000, 0x1000)
AddrRange('A', 0x1000, '4 KB')
>>> a.add('B', 0x2000, 0x1000)
AddrRange('B', 0x2000, '4 KB')
>>> a.add('C', 0x3000, 0x800)
AddrRange('C', 0x3000, '2 KB')
>>> m = a.match_addrrange(AddrRange(0x1800, 0x1000))
>>> m
AddrMap()
>>> list(m)
[AddrRange('A', 0x1000, '4 KB'), AddrRange('B', 0x2000, '4 KB')]
exception icdutil.addrmap.Conflict(one, other)[source]

Bases: RuntimeError

AddrMap Conflict Error.