blob: 4b8d20ac6746cc46eb7f75c1e978729a2b409311 [file] [log] [blame]
# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
'''OTBN ELF file handling'''
import re
import struct
from typing import Optional, Dict
from shared.elf import read_elf
from .decode import decode_words
from .sim import LoopWarps, OTBNSim
def _get_exp_end_addr(symbols: Dict[str, int]) -> Optional[int]:
'''Get the expected end address for a run of this binary
This is the value of the ELF symbol _expected_end_addr. If the symbol
doesn't exist, returns None.
'''
if '_expected_end_addr' in symbols:
return symbols['_expected_end_addr']
return None
def _get_loop_warps(symbols: Dict[str, int]) -> LoopWarps:
'''Return a list of the requested loop warps
These are read in the format described in sim.py. A warp is specified as a
symbol of the form
_loop_warp_FROM_TO
pointing at the address where it should take effect. If a symbol specifies
TO < FROM, we raise a RuntimeError. If there are multiple symbols that
specify warps at a particular address/count pair, we raise a RuntimeError.
'''
pat = re.compile(r'_loop_warp_([0-9]+)_([0-9]+)')
ret = {} # type: LoopWarps
for sym in symbols.keys():
match = pat.match(sym)
if match is None:
continue
count_from = int(match.group(1))
count_to = int(match.group(2))
addr = symbols[sym]
assert isinstance(addr, int)
if count_to < count_from:
raise RuntimeError('Loop warp instruction from symbol {!r}'
'implies an infinite loop (because {} < {}).'
.format(sym, count_to, count_from))
at_addr = ret.setdefault(addr, {})
if count_from in at_addr:
raise RuntimeError('Multiple symbols specify a loop warp at {:#x} '
'with a starting count of {}.'
.format(addr, count_from))
at_addr[count_from] = count_to
return ret
def load_elf(sim: OTBNSim, path: str) -> Optional[int]:
'''Load ELF file at path and inject its contents into sim
Returns the expected end address, if set, otherwise None.
'''
(imem_bytes, dmem_bytes, symbols) = read_elf(path)
# Collect imem bytes into 32-bit words and set the validity bit for each
assert len(imem_bytes) & 3 == 0
imem_words = [(True, w32s[0])
for w32s in struct.iter_unpack('<I', imem_bytes)]
imem_insns = decode_words(0, imem_words)
loop_warps = _get_loop_warps(symbols)
exp_end = _get_exp_end_addr(symbols)
sim.load_program(imem_insns)
sim.loop_warps = loop_warps
sim.load_data(dmem_bytes, has_validity=False)
return exp_end