Mercurial > lcfOS
annotate python/utils/hexfile.py @ 354:5477e499b039
Added some sort of string functionality
author | Windel Bouwman |
---|---|
date | Thu, 13 Mar 2014 18:59:06 +0100 |
parents | b145f8e6050b |
children | 67a584582aee |
rev | line source |
---|---|
104 | 1 import os |
244 | 2 import struct |
245 | 3 import binascii |
4 | |
5 DATA = 0 | |
6 EOF = 1 | |
7 EXTLINADR = 4 | |
104 | 8 |
9 class HexFileException(Exception): | |
233 | 10 pass |
104 | 11 |
292 | 12 |
104 | 13 def parseHexLine(line): |
233 | 14 """ Parses a hexfile line into three parts """ |
15 line = line[1:] # Remove ':' | |
16 nums = bytes.fromhex(line) | |
17 bytecount = nums[0] | |
18 if len(nums) != bytecount + 5: | |
19 raise HexFileException('byte count field incorrect') | |
20 crc = sum(nums) | |
21 if (crc & 0xFF) != 0: | |
22 raise HexFileException('crc incorrect') | |
244 | 23 address = struct.unpack('>H', nums[1:3])[0] |
233 | 24 typ = nums[3] |
25 data = nums[4:-1] | |
26 return (address, typ, data) | |
27 | |
244 | 28 def makeHexLine(address, typ, data=bytes()): |
29 bytecount = len(data) | |
30 nums = bytearray() | |
31 nums.append(bytecount) | |
32 nums.extend(struct.pack('>H', address)) | |
33 nums.append(typ) | |
34 nums.extend(data) | |
35 crc = sum(nums) | |
36 crc = ((~crc) + 1) & 0xFF | |
37 nums.append(crc) | |
245 | 38 line = ':' + binascii.hexlify(nums).decode('ascii') |
244 | 39 return line |
40 | |
41 def chunks(data, csize=16): | |
42 idx = 0 | |
43 while idx < len(data): | |
44 s = min(len(data) - idx, csize) | |
45 yield data[idx:idx+s] | |
46 idx += s | |
104 | 47 |
245 | 48 def hexfields(f): |
49 for line in f: | |
50 line = line.strip() # Strip spaces and newlines | |
51 if not line: | |
52 continue # Skip empty lines | |
53 if line[0] != ':': | |
54 continue # Skip lines that do not start with a ':' | |
55 yield parseHexLine(line) | |
56 | |
57 | |
104 | 58 class HexFile: |
233 | 59 """ Represents an intel hexfile """ |
240 | 60 def __init__(self): |
61 self.regions = [] | |
62 self.startAddress = 0 | |
104 | 63 |
233 | 64 def load(self, f): |
245 | 65 endOfFile = False |
66 ext = 0 | |
67 for address, typ, data in hexfields(f): | |
68 if endOfFile: | |
69 raise HexFileException('hexfile line after end of file record') | |
104 | 70 if typ == 0x0: # Data record |
245 | 71 self.addRegion(address + ext, data) |
72 elif typ == EXTLINADR: # Extended linear address record | |
73 ext = (struct.unpack('>H', data[0:2])[0]) << 16 | |
74 elif typ == EOF: # End of file record | |
75 if len(data) != 0: | |
76 raise HexFileException('end of file not empty') | |
77 endOfFile = True | |
104 | 78 elif typ == 0x5: # Start address record (where IP goes after loading) |
245 | 79 self.startAddress = struct.unpack('>I', data[0:4])[0] |
104 | 80 else: |
245 | 81 raise HexFileException('record type {0} not implemented'.format(typ)) |
233 | 82 |
83 def __repr__(self): | |
306 | 84 size = sum(r.Size for r in self.regions) |
246 | 85 return 'Hexfile containing {} bytes'.format(size) |
244 | 86 |
87 def dump(self): | |
88 print(self) | |
233 | 89 for r in self.regions: |
244 | 90 print(r) |
91 | |
92 def __eq__(self, other): | |
93 regions = self.regions | |
94 oregions = other.regions | |
95 if len(regions) != len(oregions): | |
96 return False | |
97 return all(rs == ro for rs, ro in zip(regions, oregions)) | |
98 | |
99 def addRegion(self, address, data): | |
100 r = HexFileRegion(address, data) | |
101 self.regions.append(r) | |
245 | 102 self.check() |
103 | |
104 def check(self): | |
244 | 105 self.regions.sort(key=lambda r: r.address) |
245 | 106 change = True |
107 while change and len(self.regions) > 1: | |
108 change = False | |
109 for r1, r2 in zip(self.regions[:-1], self.regions[1:]): | |
110 if r1.EndAddress == r2.address: | |
111 r1.addData(r2.data) | |
112 self.regions.remove(r2) | |
113 change = True | |
251
6ed3d3a82a63
Added another c3 example. First import attempt
Windel Bouwman
parents:
246
diff
changeset
|
114 elif r1.EndAddress > r2.address: |
6ed3d3a82a63
Added another c3 example. First import attempt
Windel Bouwman
parents:
246
diff
changeset
|
115 raise HexFileException('Overlapping regions') |
245 | 116 |
246 | 117 def merge(self, other): |
118 for r in other.regions: | |
119 self.addRegion(r.address, r.data) | |
233 | 120 |
121 def save(self, f): | |
245 | 122 def emit(address, typ, data=bytes()): |
123 print(makeHexLine(address, typ, data), file=f) | |
233 | 124 for r in self.regions: |
245 | 125 ext = r.address & 0xFFFF0000 |
126 emit(0, EXTLINADR, struct.pack('>H', ext >> 16)) | |
127 address = r.address - ext | |
244 | 128 for chunk in chunks(r.data): |
245 | 129 if address >= 0x10000: |
130 ext += 0x10000 | |
131 emit(0, EXTLINADR, struct.pack('>H', ext >> 16)) | |
132 address -= 0x10000 | |
133 emit(address, DATA, chunk) | |
134 address += len(chunk) | |
135 emit(0, EOF) | |
233 | 136 |
292 | 137 |
104 | 138 class HexFileRegion: |
244 | 139 def __init__(self, address, data = bytes()): |
140 self.address = address | |
141 self.data = data | |
142 | |
143 def __repr__(self): | |
245 | 144 return 'Region at 0x{:08X} of {} bytes'.format(self.address, len(self.data)) |
244 | 145 |
146 def __eq__(self, other): | |
147 return (self.address, self.data) == (other.address, other.data) | |
148 | |
245 | 149 def addData(self, d): |
150 self.data = self.data + d | |
151 | |
244 | 152 @property |
306 | 153 def Size(self): |
154 return len(self.data) | |
155 | |
156 @property | |
244 | 157 def EndAddress(self): |
158 return self.address + len(self.data) |