blob: f77e9a467714d93e85176dfa5475ad52bc4ecef6 [file] [log] [blame]
# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
import random
from typing import Dict, List, Tuple
class InitData:
'''Initialised data, written to the random binary to be loaded.'''
def __init__(self, values: Dict[int, int]):
self._values = values
def as_segs(self) -> Dict[int, List[int]]:
'''Convert from dictionary representation to segments
The dictionary representation is keyed by 4-byte aligned addresses and
has values 32-bit unsigned numbers. The segment representation maps
4-byte aligned base addresses to lists of 32-bit unsigned numbers (and
the segments are disjoint).
'''
segs = {}
cur_seg = None
for addr, value in self._values.items():
assert addr & 3 == 0
assert 0 <= value < (1 << 32)
if cur_seg is not None:
base_addr, next_addr, values = cur_seg
if addr == next_addr:
values.append(value)
cur_seg = (base_addr, next_addr + 4, values)
continue
assert base_addr not in segs
segs[base_addr] = values
cur_seg = None
assert cur_seg is None
cur_seg = (addr, addr + 4, [value])
if cur_seg is not None:
base_addr, next_addr, values = cur_seg
assert base_addr not in segs
segs[base_addr] = values
return segs
def as_json(self) -> List[Tuple[int, int]]:
'''Return init_data, as it should be serialized to json'''
return [(addr, data) for addr, data in self._values.items()]
def keys(self) -> List[int]:
return list(self._values.keys())
@staticmethod
def read(parsed: object) -> 'InitData':
'''Read init_data as parsed from json'''
if not isinstance(parsed, list):
raise ValueError('init_data is not a list.')
init_data = {}
for idx, item in enumerate(parsed):
if not (isinstance(item, list) and len(item) == 2):
raise ValueError('Item {} of init_data is not a length 2 list.'
.format(item))
addr, value = item
if not (isinstance(addr, int) and isinstance(value, int)):
raise ValueError('Item {} of init_data has addr or value '
'that is not an int.'
.format(idx))
if addr < 0 or addr & 3:
raise ValueError('Item {} of init_data has '
'an invalid address, 0x{:x}.'
.format(idx, addr))
if not (0 <= value < (1 << 32)):
raise ValueError('Item {} of init_data has '
'invalid data ({} is not a u32).'
.format(idx, value))
init_data[addr] = value
return InitData(init_data)
@staticmethod
def gen(dmem_size: int) -> 'InitData':
'''Generate some initialised data
This will be inserted into the program as initialised data (pre-loaded).
The dictionary maps (word-aligned) byte addresses to u32 values.
'''
assert dmem_size > 0
values = {}
byte_width = 32
word_width = byte_width // 4
hi_wword = dmem_size // byte_width - 1
for blob_idx in range(random.randint(1, 4)):
blob_wword = random.randint(0, hi_wword)
blob_addr = byte_width * blob_wword
for word_idx in range(word_width):
values[blob_addr + 4 * word_idx] = random.getrandbits(32)
return InitData(values)