727f043747
* Scripts: option bytes check * Scripts: option bytes set * Scripts: openocd config * Scripts: increased readability, process IPCCBR option byte * Scripts: split dap_ob.py * Updater: process IPCCBR option byte * Scripts: move chip-related functions to chip definition * Scripts: freeze CPU registers * Scripts: flash programming routine * ob.py * otp.py * otp: handle errors correctly * downgrade to python 3.9 * correct type hinting * Scripts: fix path to ob.data Co-authored-by: あく <alleteam@gmail.com>
96 lines
3.0 KiB
Python
96 lines
3.0 KiB
Python
from dataclasses import dataclass
|
|
from flipper.utils.openocd import OpenOCD
|
|
|
|
|
|
@dataclass
|
|
class RegisterBitDefinition:
|
|
name: str
|
|
offset: int
|
|
size: int
|
|
value: int = 0
|
|
|
|
|
|
class Register32:
|
|
def __init__(self, address: int, definition_list: list[RegisterBitDefinition]):
|
|
self.__dict__["names"] = [definition.name for definition in definition_list]
|
|
self.names = [definition.name for definition in definition_list] # typecheck
|
|
self.address = address
|
|
self.definition_list = definition_list
|
|
|
|
# Validate that the definitions are not overlapping
|
|
for i in range(len(definition_list)):
|
|
for j in range(i + 1, len(definition_list)):
|
|
if self._is_overlapping(definition_list[i], definition_list[j]):
|
|
raise ValueError("Register definitions are overlapping")
|
|
|
|
self.freezed = True
|
|
|
|
def _is_overlapping(
|
|
self, a: RegisterBitDefinition, b: RegisterBitDefinition
|
|
) -> bool:
|
|
if a.offset + a.size <= b.offset:
|
|
return False
|
|
if b.offset + b.size <= a.offset:
|
|
return False
|
|
return True
|
|
|
|
def _get_definition(self, name: str) -> RegisterBitDefinition:
|
|
for definition in self.definition_list:
|
|
if definition.name == name:
|
|
return definition
|
|
raise ValueError(f"Register definition '{name}' not found")
|
|
|
|
def get_definition_list(self) -> list[RegisterBitDefinition]:
|
|
return self.definition_list
|
|
|
|
def get_address(self) -> int:
|
|
return self.address
|
|
|
|
def set_reg_value(self, name: str, value: int):
|
|
definition = self._get_definition(name)
|
|
if value > (1 << definition.size) - 1:
|
|
raise ValueError(
|
|
f"Value {value} is too large for register definition '{name}'"
|
|
)
|
|
definition.value = value
|
|
|
|
def get_reg_value(self, name: str) -> int:
|
|
definition = self._get_definition(name)
|
|
return definition.value
|
|
|
|
def __getattr__(self, attr):
|
|
if str(attr) in self.names:
|
|
return self.get_reg_value(str(attr))
|
|
else:
|
|
return self.__dict__[attr]
|
|
|
|
def __setattr__(self, attr, value):
|
|
if str(attr) in self.names:
|
|
self.set_reg_value(str(attr), value)
|
|
else:
|
|
if attr in self.__dict__ or "freezed" not in self.__dict__:
|
|
self.__dict__[attr] = value
|
|
else:
|
|
raise AttributeError(f"Attribute '{attr}' not found")
|
|
|
|
def __dir__(self):
|
|
return self.names
|
|
|
|
def set(self, value: int):
|
|
for definition in self.definition_list:
|
|
definition.value = (value >> definition.offset) & (
|
|
(1 << definition.size) - 1
|
|
)
|
|
|
|
def get(self) -> int:
|
|
value = 0
|
|
for definition in self.definition_list:
|
|
value |= definition.value << definition.offset
|
|
return value
|
|
|
|
def load(self, openocd: OpenOCD):
|
|
self.set(openocd.read_32(self.address))
|
|
|
|
def store(self, openocd: OpenOCD):
|
|
openocd.write_32(self.address, self.get())
|