Mercurial > lcfOS
comparison python/hexfile.py @ 245:66912720d712
Added grinder
author | Windel Bouwman |
---|---|
date | Wed, 24 Jul 2013 22:40:29 +0200 |
parents | 58155c7c4a8e |
children | f254b87258e6 |
comparison
equal
deleted
inserted
replaced
244:58155c7c4a8e | 245:66912720d712 |
---|---|
1 import os | 1 import os |
2 import struct | 2 import struct |
3 import binascii | |
4 | |
5 DATA = 0 | |
6 EOF = 1 | |
7 EXTLINADR = 4 | |
3 | 8 |
4 class HexFileException(Exception): | 9 class HexFileException(Exception): |
5 pass | 10 pass |
6 | 11 |
7 def parseHexLine(line): | 12 def parseHexLine(line): |
27 nums.append(typ) | 32 nums.append(typ) |
28 nums.extend(data) | 33 nums.extend(data) |
29 crc = sum(nums) | 34 crc = sum(nums) |
30 crc = ((~crc) + 1) & 0xFF | 35 crc = ((~crc) + 1) & 0xFF |
31 nums.append(crc) | 36 nums.append(crc) |
32 line = ':' + ''.join(['{:02X}'.format(b) for b in nums]) | 37 line = ':' + binascii.hexlify(nums).decode('ascii') |
33 return line | 38 return line |
34 | 39 |
35 def chunks(data, csize=16): | 40 def chunks(data, csize=16): |
36 idx = 0 | 41 idx = 0 |
37 while idx < len(data): | 42 while idx < len(data): |
38 s = min(len(data) - idx, csize) | 43 s = min(len(data) - idx, csize) |
39 yield data[idx:idx+s] | 44 yield data[idx:idx+s] |
40 idx += s | 45 idx += s |
41 | 46 |
47 def hexfields(f): | |
48 for line in f: | |
49 line = line.strip() # Strip spaces and newlines | |
50 if not line: | |
51 continue # Skip empty lines | |
52 if line[0] != ':': | |
53 continue # Skip lines that do not start with a ':' | |
54 yield parseHexLine(line) | |
55 | |
56 | |
42 class HexFile: | 57 class HexFile: |
43 """ Represents an intel hexfile """ | 58 """ Represents an intel hexfile """ |
44 def __init__(self): | 59 def __init__(self): |
45 self.regions = [] | 60 self.regions = [] |
46 self.startAddress = 0 | 61 self.startAddress = 0 |
47 | 62 |
48 def load(self, f): | 63 def load(self, f): |
49 endOfFile = False | 64 endOfFile = False |
50 offset = 0 | 65 ext = 0 |
51 startAddress = 0 | 66 for address, typ, data in hexfields(f): |
52 curAddress = 0 | 67 if endOfFile: |
53 curData = bytearray() | 68 raise HexFileException('hexfile line after end of file record') |
54 for line in f: | |
55 line = line.strip() # Strip spaces and newlines | |
56 if not line: continue # Skip empty lines | |
57 if line[0] != ':': continue # Skip lines that do not start with a ':' | |
58 if endOfFile: raise HexFileException('hexfile line after end of file record') | |
59 address, typ, data = parseHexLine(line) | |
60 if typ == 0x0: # Data record | 69 if typ == 0x0: # Data record |
61 address += offset # Fix address with offset | 70 self.addRegion(address + ext, data) |
62 # Append data | 71 elif typ == EXTLINADR: # Extended linear address record |
63 if address == curAddress: | 72 ext = (struct.unpack('>H', data[0:2])[0]) << 16 |
64 curData += data | 73 elif typ == EOF: # End of file record |
65 curAddress += len(data) | 74 if len(data) != 0: |
66 else: | 75 raise HexFileException('end of file not empty') |
67 if curData: | 76 endOfFile = True |
68 self.regions.append(HexFileRegion(startAddress, bytes(curData))) | |
69 startAddress = address | |
70 curAddress = address + len(data) | |
71 curData = bytearray(data) | |
72 elif typ == 0x4: # Extended linear address record | |
73 offset = ((data[0] << 8) + data[1]) << 16 | |
74 elif typ == 0x1: # End of file record | |
75 if len(data) != 0: | |
76 raise HexFileException('end of file record must contain no data') | |
77 endOfFile = True | |
78 elif typ == 0x5: # Start address record (where IP goes after loading) | 77 elif typ == 0x5: # Start address record (where IP goes after loading) |
79 self.startAddress = (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3] | 78 self.startAddress = struct.unpack('>I', data[0:4])[0] |
80 else: | 79 else: |
81 raise HexFileException('record type {0} not implemented'.format(typ)) | 80 raise HexFileException('record type {0} not implemented'.format(typ)) |
82 print(hex(address), typ, data) | |
83 # After all lines: | |
84 if curData: | |
85 self.regions.append(HexFileRegion(startAddress, bytes(curData))) | |
86 | 81 |
87 def __repr__(self): | 82 def __repr__(self): |
88 return 'Hexfile with {} regions'.format(len(self.regions)) | 83 return 'Hexfile with {} regions'.format(len(self.regions)) |
89 | 84 |
90 def dump(self): | 85 def dump(self): |
99 return False | 94 return False |
100 return all(rs == ro for rs, ro in zip(regions, oregions)) | 95 return all(rs == ro for rs, ro in zip(regions, oregions)) |
101 | 96 |
102 def addRegion(self, address, data): | 97 def addRegion(self, address, data): |
103 r = HexFileRegion(address, data) | 98 r = HexFileRegion(address, data) |
104 # TODO: check touches | |
105 self.regions.append(r) | 99 self.regions.append(r) |
100 self.check() | |
101 | |
102 def check(self): | |
106 self.regions.sort(key=lambda r: r.address) | 103 self.regions.sort(key=lambda r: r.address) |
104 if len(self.regions) > 1: | |
105 for r1, r2 in zip(self.regions[:-1], self.regions[1:]): | |
106 if r1.EndAddress > r2.address: | |
107 raise HexFileException('Overlapping regions') | |
108 change = True | |
109 while change and len(self.regions) > 1: | |
110 change = False | |
111 for r1, r2 in zip(self.regions[:-1], self.regions[1:]): | |
112 if r1.EndAddress == r2.address: | |
113 r1.addData(r2.data) | |
114 self.regions.remove(r2) | |
115 change = True | |
116 | |
107 | 117 |
108 def save(self, f): | 118 def save(self, f): |
119 def emit(address, typ, data=bytes()): | |
120 print(makeHexLine(address, typ, data), file=f) | |
109 for r in self.regions: | 121 for r in self.regions: |
110 offset = 0 | 122 ext = r.address & 0xFFFF0000 |
123 emit(0, EXTLINADR, struct.pack('>H', ext >> 16)) | |
124 address = r.address - ext | |
111 for chunk in chunks(r.data): | 125 for chunk in chunks(r.data): |
112 print(makeHexLine(r.address + offset, 0x0, bytes(r.data[offset:offset+16])), file=f) | 126 if address >= 0x10000: |
113 offset += len(chunk) | 127 ext += 0x10000 |
114 print(makeHexLine(0, 0x1, bytes()), file=f) | 128 emit(0, EXTLINADR, struct.pack('>H', ext >> 16)) |
129 address -= 0x10000 | |
130 emit(address, DATA, chunk) | |
131 address += len(chunk) | |
132 emit(0, EOF) | |
115 | 133 |
116 class HexFileRegion: | 134 class HexFileRegion: |
117 def __init__(self, address, data = bytes()): | 135 def __init__(self, address, data = bytes()): |
118 self.address = address | 136 self.address = address |
119 self.data = data | 137 self.data = data |
120 | 138 |
121 def __repr__(self): | 139 def __repr__(self): |
122 return 'Region at 0x{0:X} of {1} bytes'.format(self.address, len(self.data)) | 140 return 'Region at 0x{:08X} of {} bytes'.format(self.address, len(self.data)) |
123 | 141 |
124 def __eq__(self, other): | 142 def __eq__(self, other): |
125 return (self.address, self.data) == (other.address, other.data) | 143 return (self.address, self.data) == (other.address, other.data) |
144 | |
145 def addData(self, d): | |
146 self.data = self.data + d | |
126 | 147 |
127 @property | 148 @property |
128 def EndAddress(self): | 149 def EndAddress(self): |
129 return self.address + len(self.data) | 150 return self.address + len(self.data) |
130 | 151 |
131 | 152 |
132 if __name__ == '__main__': | |
133 h = HexFile() | |
134 print(h) | |
135 """ Test hexfile implementation with some hexfile """ | |
136 h1 = HexFile() | |
137 with open('audio.hex', 'r') as f: | |
138 h1.load(f) | |
139 print(h1) | |
140 |