Mercurial > lcfOS
comparison 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 |
comparison
equal
deleted
inserted
replaced
290:7b38782ed496 | 292:534b94b40aa8 |
---|---|
1 import os | |
2 import struct | |
3 import binascii | |
4 | |
5 DATA = 0 | |
6 EOF = 1 | |
7 EXTLINADR = 4 | |
8 | |
9 class HexFileException(Exception): | |
10 pass | |
11 | |
12 | |
13 def parseHexLine(line): | |
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') | |
23 address = struct.unpack('>H', nums[1:3])[0] | |
24 typ = nums[3] | |
25 data = nums[4:-1] | |
26 return (address, typ, data) | |
27 | |
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) | |
38 line = ':' + binascii.hexlify(nums).decode('ascii') | |
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 | |
47 | |
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 | |
58 class HexFile: | |
59 """ Represents an intel hexfile """ | |
60 def __init__(self): | |
61 self.regions = [] | |
62 self.startAddress = 0 | |
63 | |
64 def load(self, f): | |
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') | |
70 if typ == 0x0: # Data record | |
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 | |
78 elif typ == 0x5: # Start address record (where IP goes after loading) | |
79 self.startAddress = struct.unpack('>I', data[0:4])[0] | |
80 else: | |
81 raise HexFileException('record type {0} not implemented'.format(typ)) | |
82 | |
83 def __repr__(self): | |
84 size = sum(len(r.data) for r in self.regions) | |
85 return 'Hexfile containing {} bytes'.format(size) | |
86 | |
87 def dump(self): | |
88 print(self) | |
89 for r in self.regions: | |
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) | |
102 self.check() | |
103 | |
104 def check(self): | |
105 self.regions.sort(key=lambda r: r.address) | |
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 | |
114 elif r1.EndAddress > r2.address: | |
115 raise HexFileException('Overlapping regions') | |
116 | |
117 def merge(self, other): | |
118 for r in other.regions: | |
119 self.addRegion(r.address, r.data) | |
120 | |
121 def save(self, f): | |
122 def emit(address, typ, data=bytes()): | |
123 print(makeHexLine(address, typ, data), file=f) | |
124 for r in self.regions: | |
125 ext = r.address & 0xFFFF0000 | |
126 emit(0, EXTLINADR, struct.pack('>H', ext >> 16)) | |
127 address = r.address - ext | |
128 for chunk in chunks(r.data): | |
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) | |
136 | |
137 | |
138 class HexFileRegion: | |
139 def __init__(self, address, data = bytes()): | |
140 self.address = address | |
141 self.data = data | |
142 | |
143 def __repr__(self): | |
144 return 'Region at 0x{:08X} of {} bytes'.format(self.address, len(self.data)) | |
145 | |
146 def __eq__(self, other): | |
147 return (self.address, self.data) == (other.address, other.data) | |
148 | |
149 def addData(self, d): | |
150 self.data = self.data + d | |
151 | |
152 @property | |
153 def EndAddress(self): | |
154 return self.address + len(self.data) |