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