Mercurial > lcfOS
diff python/utils/hexfile.py @ 292:534b94b40aa8
Fixup reorganize
author | Windel Bouwman |
---|---|
date | Wed, 27 Nov 2013 08:06:42 +0100 |
parents | python/hexfile.py@6ed3d3a82a63 |
children | b145f8e6050b |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/python/utils/hexfile.py Wed Nov 27 08:06:42 2013 +0100 @@ -0,0 +1,154 @@ +import os +import struct +import binascii + +DATA = 0 +EOF = 1 +EXTLINADR = 4 + +class HexFileException(Exception): + pass + + +def parseHexLine(line): + """ Parses a hexfile line into three parts """ + line = line[1:] # Remove ':' + nums = bytes.fromhex(line) + bytecount = nums[0] + if len(nums) != bytecount + 5: + raise HexFileException('byte count field incorrect') + crc = sum(nums) + if (crc & 0xFF) != 0: + raise HexFileException('crc incorrect') + address = struct.unpack('>H', nums[1:3])[0] + typ = nums[3] + data = nums[4:-1] + return (address, typ, data) + +def makeHexLine(address, typ, data=bytes()): + bytecount = len(data) + nums = bytearray() + nums.append(bytecount) + nums.extend(struct.pack('>H', address)) + nums.append(typ) + nums.extend(data) + crc = sum(nums) + crc = ((~crc) + 1) & 0xFF + nums.append(crc) + line = ':' + binascii.hexlify(nums).decode('ascii') + return line + +def chunks(data, csize=16): + idx = 0 + while idx < len(data): + s = min(len(data) - idx, csize) + yield data[idx:idx+s] + idx += s + +def hexfields(f): + for line in f: + line = line.strip() # Strip spaces and newlines + if not line: + continue # Skip empty lines + if line[0] != ':': + continue # Skip lines that do not start with a ':' + yield parseHexLine(line) + + +class HexFile: + """ Represents an intel hexfile """ + def __init__(self): + self.regions = [] + self.startAddress = 0 + + def load(self, f): + endOfFile = False + ext = 0 + for address, typ, data in hexfields(f): + if endOfFile: + raise HexFileException('hexfile line after end of file record') + if typ == 0x0: # Data record + self.addRegion(address + ext, data) + elif typ == EXTLINADR: # Extended linear address record + ext = (struct.unpack('>H', data[0:2])[0]) << 16 + elif typ == EOF: # End of file record + if len(data) != 0: + raise HexFileException('end of file not empty') + endOfFile = True + elif typ == 0x5: # Start address record (where IP goes after loading) + self.startAddress = struct.unpack('>I', data[0:4])[0] + else: + raise HexFileException('record type {0} not implemented'.format(typ)) + + def __repr__(self): + size = sum(len(r.data) for r in self.regions) + return 'Hexfile containing {} bytes'.format(size) + + def dump(self): + print(self) + for r in self.regions: + print(r) + + def __eq__(self, other): + regions = self.regions + oregions = other.regions + if len(regions) != len(oregions): + return False + return all(rs == ro for rs, ro in zip(regions, oregions)) + + def addRegion(self, address, data): + r = HexFileRegion(address, data) + self.regions.append(r) + self.check() + + def check(self): + self.regions.sort(key=lambda r: r.address) + change = True + while change and len(self.regions) > 1: + change = False + for r1, r2 in zip(self.regions[:-1], self.regions[1:]): + if r1.EndAddress == r2.address: + r1.addData(r2.data) + self.regions.remove(r2) + change = True + elif r1.EndAddress > r2.address: + raise HexFileException('Overlapping regions') + + def merge(self, other): + for r in other.regions: + self.addRegion(r.address, r.data) + + def save(self, f): + def emit(address, typ, data=bytes()): + print(makeHexLine(address, typ, data), file=f) + for r in self.regions: + ext = r.address & 0xFFFF0000 + emit(0, EXTLINADR, struct.pack('>H', ext >> 16)) + address = r.address - ext + for chunk in chunks(r.data): + if address >= 0x10000: + ext += 0x10000 + emit(0, EXTLINADR, struct.pack('>H', ext >> 16)) + address -= 0x10000 + emit(address, DATA, chunk) + address += len(chunk) + emit(0, EOF) + + +class HexFileRegion: + def __init__(self, address, data = bytes()): + self.address = address + self.data = data + + def __repr__(self): + return 'Region at 0x{:08X} of {} bytes'.format(self.address, len(self.data)) + + def __eq__(self, other): + return (self.address, self.data) == (other.address, other.data) + + def addData(self, d): + self.data = self.data + d + + @property + def EndAddress(self): + return self.address + len(self.data)