ihex.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. """
  2. # TOP2049 Open Source programming suite
  3. #
  4. # IHEX file layout
  5. #
  6. # Copyright (c) 2013 Michael Buesch <m@bues.ch>
  7. #
  8. # This program is free software; you can redistribute it and/or modify
  9. # it under the terms of the GNU General Public License as published by
  10. # the Free Software Foundation; either version 2 of the License, or
  11. # (at your option) any later version.
  12. #
  13. # This program is distributed in the hope that it will be useful,
  14. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. # GNU General Public License for more details.
  17. #
  18. # You should have received a copy of the GNU General Public License along
  19. # with this program; if not, write to the Free Software Foundation, Inc.,
  20. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  21. """
  22. from .util import *
  23. class AddressRange(object):
  24. """Address range type."""
  25. def __init__(self, startAddress = 0, endAddress = -1):
  26. # endAddress of -1 means "to the end of the image".
  27. assert(startAddress >= 0)
  28. assert(endAddress >= -1)
  29. assert(startAddress <= endAddress or endAddress == -1)
  30. self.startAddress = startAddress
  31. self.endAddress = endAddress
  32. def overlaps(self, other):
  33. """Check if self overlaps with other."""
  34. if (other.startAddress <= self.endAddress or self.endAddress < 0) and\
  35. (other.endAddress >= self.startAddress or other.endAddress < 0):
  36. return True
  37. return False
  38. @classmethod
  39. def overlapsAny(cls, addressRangeList, addressRange):
  40. """Check if 'addressRange' overlaps with any
  41. AddressRange in 'addressRangeList'"""
  42. return any(r.overlaps(addressRange) for r in addressRangeList)
  43. class IHexInterpreter(object):
  44. """Generic interpreter for a cumulative IHEX file.
  45. This class must be subclassed to be usable."""
  46. # Definition of the address ranges.
  47. # For each memory area type, several possible address
  48. # ranges can be defined. They are tried first to last.
  49. # Override these in the subclass.
  50. progmemRanges = None
  51. eepromRanges = None
  52. fuseRanges = None
  53. lockRanges = None
  54. ramRanges = None
  55. uilRanges = None
  56. # Definition of default memory values.
  57. # Override these in the subclass.
  58. progmemDefaultBytes = b"\xFF"
  59. eepromDefaultBytes = b"\xFF"
  60. fuseDefaultBytes = b"\xFF"
  61. lockDefaultBytes = b"\xFF"
  62. ramDefaultBytes = b"\x00"
  63. uilDefaultBytes = b"\xFF"
  64. def __init__(self):
  65. self.__ihexData = None
  66. self.__progmem = None
  67. self.__eeprom = None
  68. self.__fusebits = None
  69. self.__lockbits = None
  70. self.__ram = None
  71. self.__uil = None
  72. def cumulativeSupported(self):
  73. """Returns True, if parsing of cumulative IHEX files
  74. is supported by the implementation."""
  75. return self.progmemRanges or\
  76. self.eepromRanges or\
  77. self.fuseRanges or\
  78. self.lockRanges or\
  79. self.ramRanges or\
  80. self.uilRanges
  81. def interpret(self, ihexData):
  82. self.__ihexData = ihexData
  83. usedRanges = []
  84. self.__progmem = self.tryExtract(ihexData, self.progmemDefaultBytes,
  85. usedRanges, self.progmemRanges)
  86. self.__eeprom = self.tryExtract(ihexData, self.eepromDefaultBytes,
  87. usedRanges, self.eepromRanges)
  88. self.__fusebits = self.tryExtract(ihexData, self.fuseDefaultBytes,
  89. usedRanges, self.fuseRanges)
  90. self.__lockbits = self.tryExtract(ihexData, self.lockDefaultBytes,
  91. usedRanges, self.lockRanges)
  92. self.__ram = self.tryExtract(ihexData, self.ramDefaultBytes,
  93. usedRanges, self.ramRanges)
  94. self.__uil = self.tryExtract(ihexData, self.uilDefaultBytes,
  95. usedRanges, self.uilRanges)
  96. def tryExtract(self, ihexData, defaultBytes, alreadyUsedRanges, tryRanges):
  97. if not tryRanges:
  98. return None
  99. for tryRange in tryRanges:
  100. if AddressRange.overlapsAny(alreadyUsedRanges, tryRange):
  101. continue
  102. image = IO_ihex().toBinary(ihexData,
  103. addressRange = tryRange,
  104. defaultBytes = defaultBytes)
  105. if not image:
  106. continue
  107. alreadyUsedRanges.append(tryRange)
  108. return image
  109. return None
  110. def getRaw(self, defaultBytes=b"\xFF"):
  111. return IO_ihex().toBinary(self.__ihexData,
  112. defaultBytes = defaultBytes)
  113. def getProgmem(self, dontInterpretSections=False):
  114. if dontInterpretSections:
  115. return self.getRaw(defaultBytes = self.progmemDefaultBytes)
  116. return self.__progmem
  117. def getEEPROM(self, dontInterpretSections=False):
  118. if dontInterpretSections:
  119. return self.getRaw(defaultBytes = self.eepromDefaultBytes)
  120. return self.__eeprom
  121. def getFusebits(self, dontInterpretSections=False):
  122. if dontInterpretSections:
  123. return self.getRaw(defaultBytes = self.fuseDefaultBytes)
  124. return self.__fusebits
  125. def getLockbits(self, dontInterpretSections=False):
  126. if dontInterpretSections:
  127. return self.getRaw(defaultBytes = self.lockDefaultBytes)
  128. return self.__lockbits
  129. def getRAM(self, dontInterpretSections=False):
  130. if dontInterpretSections:
  131. return self.getRaw(defaultBytes = self.ramDefaultBytes)
  132. return self.__ram
  133. def getUIL(self, dontInterpretSections=False):
  134. if dontInterpretSections:
  135. return self.getRaw(defaultBytes = self.uilDefaultBytes)
  136. return self.__uil