obdata.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. #!/usr/bin/env python3
  2. import logging
  3. import struct
  4. from enum import Enum
  5. from dataclasses import dataclass
  6. from typing import Tuple
  7. from array import array
  8. class OBException(ValueError):
  9. pass
  10. @dataclass
  11. class OBParams:
  12. word_idx: int
  13. bits: Tuple[int, int]
  14. name: str
  15. _OBS_descr = (
  16. OBParams(0, (0, 8), "RDP"),
  17. OBParams(0, (8, 9), "ESE"),
  18. OBParams(0, (9, 12), "BOR_LEV"),
  19. OBParams(0, (12, 13), "nRST_STOP"),
  20. OBParams(0, (13, 14), "nRST_STDBY"),
  21. OBParams(0, (14, 15), "nRSTSHDW"),
  22. OBParams(0, (15, 16), "UNUSED1"),
  23. OBParams(0, (16, 17), "IWDGSW"),
  24. OBParams(0, (17, 18), "IWDGSTOP"),
  25. OBParams(0, (18, 19), "IWGDSTDBY"), # ST's typo: IWDGSTDBY
  26. OBParams(0, (18, 19), "IWDGSTDBY"), # ST's typo: IWDGSTDBY
  27. OBParams(0, (19, 20), "WWDGSW"),
  28. OBParams(0, (20, 23), "UNUSED2"),
  29. OBParams(0, (23, 24), "nBOOT1"),
  30. OBParams(0, (24, 25), "SRAM2PE"),
  31. OBParams(0, (25, 26), "SRAM2RST"),
  32. OBParams(0, (26, 27), "nSWBOOT0"),
  33. OBParams(0, (27, 28), "nBOOT0"),
  34. OBParams(0, (28, 29), "UNUSED3"),
  35. OBParams(0, (29, 32), "AGC_TRIM"),
  36. OBParams(1, (0, 9), "PCROP1A_STRT"),
  37. OBParams(1, (9, 32), "UNUSED"),
  38. OBParams(2, (0, 9), "PCROP1A_END"),
  39. OBParams(2, (9, 31), "UNUSED"),
  40. OBParams(2, (31, 32), "PCROP_RDP"),
  41. OBParams(3, (0, 8), "WRP1A_STRT"),
  42. OBParams(3, (8, 16), "UNUSED1"),
  43. OBParams(3, (16, 24), "WRP1A_END"),
  44. OBParams(3, (24, 32), "UNUSED2"),
  45. OBParams(4, (0, 8), "WRP1B_STRT"),
  46. OBParams(4, (8, 16), "UNUSED1"),
  47. OBParams(4, (16, 24), "WRP1B_END"),
  48. OBParams(4, (24, 32), "UNUSED2"),
  49. OBParams(5, (0, 9), "PCROP1B_STRT"),
  50. OBParams(5, (9, 32), "UNUSED"),
  51. OBParams(6, (0, 9), "PCROP1B_END"),
  52. OBParams(6, (9, 32), "UNUSED"),
  53. OBParams(13, (0, 14), "IPCCDBA"),
  54. OBParams(13, (14, 32), "UNUSED"),
  55. OBParams(14, (0, 8), "SFSA"),
  56. OBParams(14, (8, 9), "FSD"),
  57. OBParams(14, (9, 12), "UNUSED1"),
  58. OBParams(14, (12, 13), "DDS"),
  59. OBParams(14, (13, 32), "UNUSED2"),
  60. OBParams(15, (0, 18), "SBRV"),
  61. OBParams(15, (18, 23), "SBRSA"),
  62. OBParams(15, (23, 24), "BRSD"),
  63. OBParams(15, (24, 25), "UNUSED1"),
  64. OBParams(15, (25, 30), "SNBRSA"),
  65. OBParams(15, (30, 31), "NBRSD"),
  66. OBParams(15, (31, 32), "C2OPT"),
  67. )
  68. _OBS = dict((param.name, param) for param in _OBS_descr)
  69. @dataclass
  70. class EncodedOBValue:
  71. value: int
  72. mask: int
  73. params: OBParams
  74. class OptionByte:
  75. class OBMode(Enum):
  76. IGNORE = 0
  77. READ = 1
  78. READ_WRITE = 2
  79. @classmethod
  80. def from_str(cls, value):
  81. if value == "r":
  82. return cls.READ
  83. elif value == "rw":
  84. return cls.READ_WRITE
  85. else:
  86. raise OBException(f"Unknown OB check mode '{value}'")
  87. def __init__(self, obstr):
  88. parts = obstr.split(":")
  89. if len(parts) != 3:
  90. raise OBException(f"Invalid OB value definition {obstr}")
  91. self.name = parts[0]
  92. self.value = int(parts[1], 16)
  93. self.mode = OptionByte.OBMode.from_str(parts[2].strip())
  94. self.descr = _OBS.get(self.name, None)
  95. if self.descr is None:
  96. raise OBException(f"Missing OB descriptor for {self.name}")
  97. def encode(self):
  98. startbit, endbit = self.descr.bits
  99. value_mask = 2 ** (endbit - startbit) - 1
  100. value_corrected = self.value & value_mask
  101. value_shifted = value_corrected << startbit
  102. value_mask_shifted = value_mask << startbit
  103. return EncodedOBValue(value_shifted, value_mask_shifted, self)
  104. def __repr__(self):
  105. return f"<OB {self.name}, 0x{self.value:x}, {self.mode} at 0x{id(self):X}>"
  106. @dataclass
  107. class ObReferenceValues:
  108. reference: bytes
  109. compare_mask: bytes
  110. write_mask: bytes
  111. class ObReferenceValuesGenerator:
  112. def __init__(self):
  113. self.compare_mask = array("I", [0] * 16)
  114. self.write_mask = array("I", [0] * 16)
  115. self.ref_values = array("I", [0] * 16)
  116. def __repr__(self):
  117. return (
  118. f"<OBRefs REFS=[{' '.join(hex(v) for v in self.ref_values)}] "
  119. f"CMPMASK=[{' '.join(hex(v) for v in self.compare_mask)}] "
  120. f"WRMASK=[{' '.join(hex(v) for v in self.write_mask)}] "
  121. )
  122. def export_values(self):
  123. export_cmpmask = array("I")
  124. for value in self.compare_mask:
  125. export_cmpmask.append(value)
  126. export_cmpmask.append(value)
  127. export_wrmask = array("I")
  128. for value in self.write_mask:
  129. export_wrmask.append(value)
  130. export_wrmask.append(value)
  131. export_refvals = array("I")
  132. for cmpmask, refval in zip(self.compare_mask, self.ref_values):
  133. export_refvals.append(refval)
  134. export_refvals.append((refval ^ 0xFFFFFFFF) & cmpmask)
  135. return export_refvals, export_cmpmask, export_wrmask
  136. def export(self):
  137. return ObReferenceValues(*map(lambda a: a.tobytes(), self.export_values()))
  138. def apply(self, ob):
  139. ob_params = ob.descr
  140. encoded_ob = ob.encode()
  141. self.compare_mask[ob_params.word_idx] |= encoded_ob.mask
  142. self.ref_values[ob_params.word_idx] |= encoded_ob.value
  143. if ob.mode == OptionByte.OBMode.READ_WRITE:
  144. self.write_mask[ob_params.word_idx] |= encoded_ob.mask
  145. class OptionBytesData:
  146. def __init__(self, obfname):
  147. self.obs = list()
  148. with open(obfname, "rt") as obfin:
  149. self.obs = list(
  150. OptionByte(line) for line in obfin if not line.startswith("#")
  151. )
  152. def gen_values(self):
  153. obref = ObReferenceValuesGenerator()
  154. converted_refs = list(obref.apply(ob) for ob in self.obs)
  155. return obref
  156. def main():
  157. with open("../../../../logs/obs.bin", "rb") as obsbin:
  158. ob_sample = obsbin.read(128)
  159. ob_sample_arr = array("I", ob_sample)
  160. print(ob_sample_arr)
  161. obd = OptionBytesData("../../ob.data")
  162. print(obd.obs)
  163. # print(obd.gen_values().export())
  164. ref, mask, wrmask = obd.gen_values().export_values()
  165. for idx in range(len(ob_sample_arr)):
  166. real_masked = ob_sample_arr[idx] & mask[idx]
  167. print(
  168. f"#{idx}: ref {ref[idx]:08x} real {real_masked:08x} ({ob_sample_arr[idx]:08x} & {mask[idx]:08x}) match {ref[idx]==real_masked}"
  169. )
  170. # print(ob_sample)
  171. if __name__ == "__main__":
  172. main()