from __future__ import annotations from typing import TypedDict from .formatting import h16 from .memory import region_for from .rom import Rom from .tables import IO_REGISTERS DTC_REGISTER_INFO_SIZE = 8 DTC_RESERVED_MODE_MASK = 0x1FFF class DtcEndpointInfo(TypedDict): address: int text: str name: str | None region: str increment: bool increment_step: int class DtcModeInfo(TypedDict): raw: int size: str bytes_per_transfer: int source_increment: bool destination_increment: bool source_increment_step: int destination_increment_step: int reserved: int reserved_set: bool class DtcCountInfo(TypedDict): raw: int transfers: int bytes: int zero_means_65536: bool class DtcRegisterInfo(TypedDict, total=False): address: int valid: bool error: str dtmr: int dtsr: int dtdr: int dtcr: int mode: DtcModeInfo source: DtcEndpointInfo destination: DtcEndpointInfo count: DtcCountInfo def _endpoint(address: int, increment: bool, increment_step: int) -> DtcEndpointInfo: name = IO_REGISTERS.get(address) return { "address": address, "text": name or h16(address), "name": name, "region": region_for(address).name, "increment": increment, "increment_step": increment_step if increment else 0, } def _mode(dtmr: int) -> DtcModeInfo: size = "word" if dtmr & 0x8000 else "byte" bytes_per_transfer = 2 if size == "word" else 1 source_increment = bool(dtmr & 0x4000) destination_increment = bool(dtmr & 0x2000) source_step = bytes_per_transfer if source_increment else 0 destination_step = bytes_per_transfer if destination_increment else 0 reserved = dtmr & DTC_RESERVED_MODE_MASK return { "raw": dtmr, "size": size, "bytes_per_transfer": bytes_per_transfer, "source_increment": source_increment, "destination_increment": destination_increment, "source_increment_step": source_step, "destination_increment_step": destination_step, "reserved": reserved, "reserved_set": reserved != 0, } def decode_dtc_register_info(rom: Rom, address: int) -> DtcRegisterInfo: """Decode the four-word DTMR/DTSR/DTDR/DTCR block pointed to by a DTC vector.""" end = address + DTC_REGISTER_INFO_SIZE - 1 if end > 0xFFFF: return { "address": address, "valid": False, "error": f"register information block {h16(address)}+{DTC_REGISTER_INFO_SIZE} exceeds page 0", } if not rom.contains(address, DTC_REGISTER_INFO_SIZE): return { "address": address, "valid": False, "error": f"register information block {h16(address)}-{h16(end)} is outside ROM image", } dtmr = rom.u16(address) dtsr = rom.u16(address + 2) dtdr = rom.u16(address + 4) dtcr = rom.u16(address + 6) mode = _mode(dtmr) transfers = 0x10000 if dtcr == 0 else dtcr return { "address": address, "valid": True, "dtmr": dtmr, "dtsr": dtsr, "dtdr": dtdr, "dtcr": dtcr, "mode": mode, "source": _endpoint(dtsr, mode["source_increment"], mode["source_increment_step"]), "destination": _endpoint(dtdr, mode["destination_increment"], mode["destination_increment_step"]), "count": { "raw": dtcr, "transfers": transfers, "bytes": transfers * mode["bytes_per_transfer"], "zero_means_65536": dtcr == 0, }, }