diff --git a/.gitignore b/.gitignore index b2ec56f..6119411 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ MANIFEST python.bat NEWS.html README.html +*.egg-info diff --git a/intelhex/__init__.py b/intelhex/__init__.py index a631b0a..add2375 100644 --- a/intelhex/__init__.py +++ b/intelhex/__init__.py @@ -140,10 +140,15 @@ def _decode_record(self, s, line=0): if record_type == 0: # data record addr += self._offset - for i in range_g(4, 4+record_length): - if not self._buf.get(addr, None) is None: + if getattr(self, "word_length", None) is not None: + word_byte = self.word_byte + else: + word_byte = 1 + for i in range_g(int(record_length/word_byte)): # FIXME:record_length should be multiples of word_byte + if not self._buf.get(addr*word_byte, None) is None: # FIXME: only check lowest byte raise AddressOverlapError(address=addr, line=line) - self._buf[addr] = bin[i] + for j in range_g(word_byte): + self._buf[addr*word_byte+j] = bin[4+i*word_byte+j] addr += 1 # FIXME: addr should be wrapped # BUT after 02 record (at 64K boundary) # and after 04 record (at 4G boundary) @@ -646,7 +651,10 @@ def write_hex_file(self, f, write_start_addr=True, eolstyle='native', byte_count bin[1] = 0 # offset msb bin[2] = 0 # offset lsb bin[3] = 4 # rectyp - high_ofs = int(cur_addr>>16) + if getattr(self, "word_length", None) is not None: + high_ofs = int(cur_addr/self.word_byte)>>16 + else: + high_ofs = int(cur_addr>>16) b = divmod(high_ofs, 256) bin[4] = b[0] # msb of high_ofs bin[5] = b[1] # lsb of high_ofs @@ -676,6 +684,8 @@ def write_hex_file(self, f, write_start_addr=True, eolstyle='native', byte_count chain_len = 1 # real chain_len bin = array('B', asbytes('\0'*(5+chain_len))) + if getattr(self, "word_length", None) is not None: + low_addr = int(low_addr/self.word_byte) b = divmod(low_addr, 256) bin[1] = b[0] # msb of low_addr bin[2] = b[1] # lsb of low_addr @@ -700,7 +710,10 @@ def write_hex_file(self, f, write_start_addr=True, eolstyle='native', byte_count else: cur_addr = maxaddr + 1 break - high_addr = int(cur_addr>>16) + if getattr(self, "word_length", None) is not None: + high_addr = int(cur_addr/self.word_byte)>>16 + else: + high_addr = int(cur_addr>>16) if high_addr > high_ofs: break @@ -1011,7 +1024,147 @@ def tobinarray(self, start=None, end=None, size=None): return bin -#/class IntelHex16bit +#/class IntelHexWord + +class IntelHexWord(IntelHex): + """Access to data as words. Intended to use with Quartus II MEM initializing HEX files.""" + + def __init__(self, source=None, word_length=16): + """Construct class from HEX file + or from instance of ordinary IntelHex class. If IntelHex object + is passed as source, the original IntelHex object should not be used + again because this class will alter it. This class leaves padding + alone unless it was precisely 0xFF. In that instance it is sign + extended to 0xFFFF. + + @param source file name of HEX file or file object + or instance of ordinary IntelHex class. + Will also accept dictionary from todict method. + @param word_length word length of each record and address of memory + """ + if isinstance(source, IntelHex): + # from ihex8 + self.padding = source.padding + self.start_addr = source.start_addr + # private members + self._buf = source._buf + self._offset = source._offset + self.word_length = word_length + if word_length%8 ==0: + self.word_byte = int(word_length/8) + else: + self.word_byte = int(word_length/8) + 1 + + elif isinstance(source, dict): + raise IntelHexError("IntelHexWord does not support initialization from dictionary yet.\n" + "Patches are welcome.") + elif isinstance(source, StrType) or getattr(source, "read", None): + # load hex file + IntelHex.__init__(self) + self.word_length = word_length + if word_length%8 ==0: + self.word_byte = int(word_length/8) + else: + self.word_byte = int(word_length/8) + 1 + self.loadhex(source) + + else: + raise ValueError("source: bad initializer type") + + if self.padding == 0x0FF: + for byte_count in range(self.word_byte-1): + self.padding = (self.padding<<8) + 0x0FF + + def __getitem__(self, addr): + """Get word from address. + Raise error if only one byte from the pair is set. + We assume a Little Endian interpretation of the hex file. + + @param addr address of word (addr8 = word_byte * addr6). + @return word if bytes exists in HEX file, or self.padding + if no data found. + """ + addr1 = addr * self.word_byte + out = 0 + is_padding =True + for byte_count in range_g(self.word_byte): + addr2 = addr1 + byte_count + byte = self._buf.get(addr2, None) + if byte != None: + out = (out<<8)+byte + is_padding = False + elif byte_count>0 and not is_padding: + raise BadAccessWord(address=addr) + if is_padding: + return self.padding + else: + return out + + + def __setitem__(self, addr, word): + """Sets the address at addr to word assuming Little Endian mode. + """ + addr_byte = addr * self.word_byte + for byte_count in range_g(self.word_byte): + addr2 = addr_byte + self.word_byte -1 - byte_count + self._buf[addr2]= word & 0x0ff + word = word >>8 + + def minaddr(self): + '''Get minimal address of HEX content in word mode. + + @return minimal address used in this object + ''' + aa = dict_keys(self._buf) + if aa == []: + return 0 + else: + return int(min(aa)/self.word_byte) + + def maxaddr(self): + '''Get maximal address of HEX content in word mode. + + @return maximal address used in this object + ''' + aa = dict_keys(self._buf) + if aa == []: + return 0 + else: + return int(max(aa)/self.word_byte) + + def tobinarray(self, start=None, end=None, size=None): + '''Convert this object to binary form as array (of 2-bytes word data). + If start and end unspecified, they will be inferred from the data. + @param start start address of output data. + @param end end address of output data (inclusive). + @param size size of the block (number of words), + used with start or end parameter. + @return array of unsigned integer data according to word bytes. + ''' + if self.word_byte<=1: + bin = array('B') + elif self.word_byte<=2: + bin = array('H') + elif self.word_byte<=4: + bin = array('L') + elif self.word_byte<=8: + bin = array('Q') + + if self._buf == {} and None in (start, end): + return bin + + if size is not None and size <= 0: + raise ValueError("tobinarray: wrong value for size") + + start, end = self._get_start_end(start, end, size) + + for addr in range_g(start, end+1): + bin.append(self[addr]) + + return bin + + +#/class IntelHexWord def hex2bin(fin, fout, start=None, end=None, size=None, pad=None): @@ -1350,5 +1503,8 @@ class NotEnoughDataError(IntelHexError): class BadAccess16bit(NotEnoughDataError): _fmt = 'Bad access at 0x%(address)X: not enough data to read 16 bit value' +class BadAccessWord(NotEnoughDataError): + _fmt = 'Bad access at 0x%(address)X: not enough data to read word value' + class EmptyIntelHexError(IntelHexError): _fmt = "Requested operation cannot be executed with empty object" diff --git a/scripts/bin2hex.py b/scripts/bin2hex.py index bc8bbbf..8a726f9 100755 --- a/scripts/bin2hex.py +++ b/scripts/bin2hex.py @@ -35,7 +35,7 @@ '''Intel HEX file format bin2hex convertor utility.''' -VERSION = '2.2' +VERSION = '2.2.1' if __name__ == '__main__': import getopt diff --git a/scripts/hex2bin.py b/scripts/hex2bin.py index 4e16d9e..3f56ec1 100755 --- a/scripts/hex2bin.py +++ b/scripts/hex2bin.py @@ -35,7 +35,7 @@ '''Intel HEX file format hex2bin convertor utility.''' -VERSION = '2.2' +VERSION = '2.2.1' if __name__ == '__main__': import getopt diff --git a/scripts/hex2dump.py b/scripts/hex2dump.py index 80b9f61..129b10c 100755 --- a/scripts/hex2dump.py +++ b/scripts/hex2dump.py @@ -35,7 +35,7 @@ """Show content of hex file as hexdump.""" -VERSION = '2.2' +VERSION = '2.2.1' USAGE = '''hex2dump: show content of hex file as hexdump. Usage: diff --git a/scripts/hexdiff.py b/scripts/hexdiff.py index 85ab3db..f9bb9db 100755 --- a/scripts/hexdiff.py +++ b/scripts/hexdiff.py @@ -37,7 +37,7 @@ of compared data. """ -VERSION = '2.2' +VERSION = '2.2.1' USAGE = '''hexdiff: diff dumps of 2 hex files. Usage: diff --git a/scripts/hexinfo.py b/scripts/hexinfo.py index 2940df4..03d4420 100755 --- a/scripts/hexinfo.py +++ b/scripts/hexinfo.py @@ -38,7 +38,7 @@ data (if any), in YAML format. """ -VERSION = '2.2' +VERSION = '2.2.1' USAGE = '''hexinfo: summarize a hex file's contents. Usage: diff --git a/scripts/hexmerge.py b/scripts/hexmerge.py index fc6877e..9359662 100755 --- a/scripts/hexmerge.py +++ b/scripts/hexmerge.py @@ -35,7 +35,7 @@ """Merge content of several hex files into one file.""" -VERSION = '2.2' +VERSION = '2.2.1' USAGE = '''hexmerge: merge content of hex files. Usage: