209 lines
6.3 KiB
Python
209 lines
6.3 KiB
Python
|
#!/usr/bin/env python3
|
||
|
|
||
|
import logging
|
||
|
import struct
|
||
|
|
||
|
from enum import Enum
|
||
|
from dataclasses import dataclass
|
||
|
from typing import Tuple
|
||
|
from array import array
|
||
|
|
||
|
|
||
|
class OBException(ValueError):
|
||
|
pass
|
||
|
|
||
|
|
||
|
@dataclass
|
||
|
class OBParams:
|
||
|
word_idx: int
|
||
|
bits: Tuple[int, int]
|
||
|
name: str
|
||
|
|
||
|
|
||
|
_OBS_descr = (
|
||
|
OBParams(0, (0, 8), "RDP"),
|
||
|
OBParams(0, (8, 9), "ESE"),
|
||
|
OBParams(0, (9, 12), "BOR_LEV"),
|
||
|
OBParams(0, (12, 13), "nRST_STOP"),
|
||
|
OBParams(0, (13, 14), "nRST_STDBY"),
|
||
|
OBParams(0, (14, 15), "nRSTSHDW"),
|
||
|
OBParams(0, (15, 16), "UNUSED1"),
|
||
|
OBParams(0, (16, 17), "IWDGSW"),
|
||
|
OBParams(0, (17, 18), "IWDGSTOP"),
|
||
|
OBParams(0, (18, 19), "IWGDSTDBY"), # ST's typo: IWDGSTDBY
|
||
|
OBParams(0, (18, 19), "IWDGSTDBY"), # ST's typo: IWDGSTDBY
|
||
|
OBParams(0, (19, 20), "WWDGSW"),
|
||
|
OBParams(0, (20, 23), "UNUSED2"),
|
||
|
OBParams(0, (23, 24), "nBOOT1"),
|
||
|
OBParams(0, (24, 25), "SRAM2PE"),
|
||
|
OBParams(0, (25, 26), "SRAM2RST"),
|
||
|
OBParams(0, (26, 27), "nSWBOOT0"),
|
||
|
OBParams(0, (27, 28), "nBOOT0"),
|
||
|
OBParams(0, (28, 29), "UNUSED3"),
|
||
|
OBParams(0, (29, 32), "AGC_TRIM"),
|
||
|
OBParams(1, (0, 9), "PCROP1A_STRT"),
|
||
|
OBParams(1, (9, 32), "UNUSED"),
|
||
|
OBParams(2, (0, 9), "PCROP1A_END"),
|
||
|
OBParams(2, (9, 31), "UNUSED"),
|
||
|
OBParams(2, (31, 32), "PCROP_RDP"),
|
||
|
OBParams(3, (0, 8), "WRP1A_STRT"),
|
||
|
OBParams(3, (8, 16), "UNUSED1"),
|
||
|
OBParams(3, (16, 24), "WRP1A_END"),
|
||
|
OBParams(3, (24, 32), "UNUSED2"),
|
||
|
OBParams(4, (0, 8), "WRP1B_STRT"),
|
||
|
OBParams(4, (8, 16), "UNUSED1"),
|
||
|
OBParams(4, (16, 24), "WRP1B_END"),
|
||
|
OBParams(4, (24, 32), "UNUSED2"),
|
||
|
OBParams(5, (0, 9), "PCROP1B_STRT"),
|
||
|
OBParams(5, (9, 32), "UNUSED"),
|
||
|
OBParams(6, (0, 9), "PCROP1B_END"),
|
||
|
OBParams(6, (9, 32), "UNUSED"),
|
||
|
OBParams(13, (0, 14), "IPCCDBA"),
|
||
|
OBParams(13, (14, 32), "UNUSED"),
|
||
|
OBParams(14, (0, 8), "SFSA"),
|
||
|
OBParams(14, (8, 9), "FSD"),
|
||
|
OBParams(14, (9, 12), "UNUSED1"),
|
||
|
OBParams(14, (12, 13), "DDS"),
|
||
|
OBParams(14, (13, 32), "UNUSED2"),
|
||
|
OBParams(15, (0, 18), "SBRV"),
|
||
|
OBParams(15, (18, 23), "SBRSA"),
|
||
|
OBParams(15, (23, 24), "BRSD"),
|
||
|
OBParams(15, (24, 25), "UNUSED1"),
|
||
|
OBParams(15, (25, 30), "SNBRSA"),
|
||
|
OBParams(15, (30, 31), "NBRSD"),
|
||
|
OBParams(15, (31, 32), "C2OPT"),
|
||
|
)
|
||
|
|
||
|
|
||
|
_OBS = dict((param.name, param) for param in _OBS_descr)
|
||
|
|
||
|
|
||
|
@dataclass
|
||
|
class EncodedOBValue:
|
||
|
value: int
|
||
|
mask: int
|
||
|
params: OBParams
|
||
|
|
||
|
|
||
|
class OptionByte:
|
||
|
class OBMode(Enum):
|
||
|
IGNORE = 0
|
||
|
READ = 1
|
||
|
READ_WRITE = 2
|
||
|
|
||
|
@classmethod
|
||
|
def from_str(cls, value):
|
||
|
if value == "r":
|
||
|
return cls.READ
|
||
|
elif value == "rw":
|
||
|
return cls.READ_WRITE
|
||
|
else:
|
||
|
raise OBException(f"Unknown OB check mode '{value}'")
|
||
|
|
||
|
def __init__(self, obstr):
|
||
|
parts = obstr.split(":")
|
||
|
if len(parts) != 3:
|
||
|
raise OBException(f"Invalid OB value definition {obstr}")
|
||
|
self.name = parts[0]
|
||
|
self.value = int(parts[1], 16)
|
||
|
self.mode = OptionByte.OBMode.from_str(parts[2].strip())
|
||
|
self.descr = _OBS.get(self.name, None)
|
||
|
if self.descr is None:
|
||
|
raise OBException(f"Missing OB descriptor for {self.name}")
|
||
|
|
||
|
def encode(self):
|
||
|
startbit, endbit = self.descr.bits
|
||
|
value_mask = 2 ** (endbit - startbit) - 1
|
||
|
value_corrected = self.value & value_mask
|
||
|
|
||
|
value_shifted = value_corrected << startbit
|
||
|
value_mask_shifted = value_mask << startbit
|
||
|
return EncodedOBValue(value_shifted, value_mask_shifted, self)
|
||
|
|
||
|
def __repr__(self):
|
||
|
return f"<OB {self.name}, 0x{self.value:x}, {self.mode} at 0x{id(self):X}>"
|
||
|
|
||
|
|
||
|
@dataclass
|
||
|
class ObReferenceValues:
|
||
|
reference: bytes
|
||
|
compare_mask: bytes
|
||
|
write_mask: bytes
|
||
|
|
||
|
|
||
|
class ObReferenceValuesGenerator:
|
||
|
def __init__(self):
|
||
|
self.compare_mask = array("I", [0] * 16)
|
||
|
self.write_mask = array("I", [0] * 16)
|
||
|
self.ref_values = array("I", [0] * 16)
|
||
|
|
||
|
def __repr__(self):
|
||
|
return (
|
||
|
f"<OBRefs REFS=[{' '.join(hex(v) for v in self.ref_values)}] "
|
||
|
f"CMPMASK=[{' '.join(hex(v) for v in self.compare_mask)}] "
|
||
|
f"WRMASK=[{' '.join(hex(v) for v in self.write_mask)}] "
|
||
|
)
|
||
|
|
||
|
def export_values(self):
|
||
|
export_cmpmask = array("I")
|
||
|
for value in self.compare_mask:
|
||
|
export_cmpmask.append(value)
|
||
|
export_cmpmask.append(value)
|
||
|
export_wrmask = array("I")
|
||
|
for value in self.write_mask:
|
||
|
export_wrmask.append(value)
|
||
|
export_wrmask.append(value)
|
||
|
export_refvals = array("I")
|
||
|
for cmpmask, refval in zip(self.compare_mask, self.ref_values):
|
||
|
export_refvals.append(refval)
|
||
|
export_refvals.append((refval ^ 0xFFFFFFFF) & cmpmask)
|
||
|
return export_refvals, export_cmpmask, export_wrmask
|
||
|
|
||
|
def export(self):
|
||
|
return ObReferenceValues(*map(lambda a: a.tobytes(), self.export_values()))
|
||
|
|
||
|
def apply(self, ob):
|
||
|
ob_params = ob.descr
|
||
|
encoded_ob = ob.encode()
|
||
|
self.compare_mask[ob_params.word_idx] |= encoded_ob.mask
|
||
|
self.ref_values[ob_params.word_idx] |= encoded_ob.value
|
||
|
if ob.mode == OptionByte.OBMode.READ_WRITE:
|
||
|
self.write_mask[ob_params.word_idx] |= encoded_ob.mask
|
||
|
|
||
|
|
||
|
class OptionBytesData:
|
||
|
def __init__(self, obfname):
|
||
|
self.obs = list()
|
||
|
with open(obfname, "rt") as obfin:
|
||
|
self.obs = list(
|
||
|
OptionByte(line) for line in obfin if not line.startswith("#")
|
||
|
)
|
||
|
|
||
|
def gen_values(self):
|
||
|
obref = ObReferenceValuesGenerator()
|
||
|
converted_refs = list(obref.apply(ob) for ob in self.obs)
|
||
|
return obref
|
||
|
|
||
|
|
||
|
def main():
|
||
|
with open("../../../../logs/obs.bin", "rb") as obsbin:
|
||
|
ob_sample = obsbin.read(128)
|
||
|
ob_sample_arr = array("I", ob_sample)
|
||
|
print(ob_sample_arr)
|
||
|
|
||
|
obd = OptionBytesData("../../ob.data")
|
||
|
print(obd.obs)
|
||
|
# print(obd.gen_values().export())
|
||
|
ref, mask, wrmask = obd.gen_values().export_values()
|
||
|
for idx in range(len(ob_sample_arr)):
|
||
|
real_masked = ob_sample_arr[idx] & mask[idx]
|
||
|
print(
|
||
|
f"#{idx}: ref {ref[idx]:08x} real {real_masked:08x} ({ob_sample_arr[idx]:08x} & {mask[idx]:08x}) match {ref[idx]==real_masked}"
|
||
|
)
|
||
|
|
||
|
# print(ob_sample)
|
||
|
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
main()
|