from __future__ import annotations from .model import EA from .tables import IO_BITFIELDS, IO_DTE_BITS, IO_PRIORITY_FIELDS, IO_REGISTERS def h8(value: int) -> str: return f"H'{value & 0xFF:02X}" def h16(value: int) -> str: return f"H'{value & 0xFFFF:04X}" def h24(value: int) -> str: return f"H'{value & 0xFFFFFF:06X}" def s8(value: int) -> int: value &= 0xFF return value - 0x100 if value & 0x80 else value def s16(value: int) -> int: value &= 0xFFFF return value - 0x10000 if value & 0x8000 else value def parse_int(text: str) -> int: return int(text.replace("H'", "0x").replace("$", "0x"), 0) def reg_list(mask: int) -> str: regs = [f"R{idx}" for idx in range(8) if mask & (1 << idx)] return "{" + ",".join(regs) + "}" if regs else "{}" def disp_text(value: int) -> str: if value < 0: return f"-{h16(-value) if value < -0xFF else h8(-value)}" return h16(value) if value > 0xFF else h8(value) def short_abs(low: int) -> str: return f"@BR:{h8(low)}" def control_reg(ccc: int, size: str) -> str: if size == "W": return "SR" if ccc == 0 else f"CR{ccc}?" return { 0: "CCR", 1: "BR", 2: "EP", 3: "DP", 4: "TP", }.get(ccc, f"CR{ccc}?") def label_for(address: int) -> str: return f"loc_{address:04X}" def label_or_h(address: int, labels: dict[int, str]) -> str: return labels.get(address, label_for(address)) def _bitfield_name(address: int, bit: int) -> str | None: priority_name = _priority_bit_name(address, bit) if priority_name: return priority_name dte_name = _dte_bit_name(address, bit) if dte_name: return dte_name return IO_BITFIELDS.get(address, {}).get(bit) def _bitfield_values(address: int, value: int) -> str: fields = IO_BITFIELDS.get(address) if not fields: return "" parts = [f"{name}={(value >> bit) & 1}" for bit, name in sorted(fields.items(), reverse=True)] return " ".join(parts) def _adcsr_semantics(value: int) -> str: channels_single = ["AN0", "AN1", "AN2", "AN3", "AN4", "AN5", "AN6", "AN7"] channels_scan = ["AN0", "AN0-AN1", "AN0-AN2", "AN0-AN3", "AN4", "AN4-AN5", "AN4-AN6", "AN4-AN7"] scan = bool(value & 0x10) channels = channels_scan[value & 0x07] if scan else channels_single[value & 0x07] mode = "scan" if scan else "single" state = "start" if value & 0x20 else "halt" interrupt = "ADI enabled" if value & 0x40 else "ADI disabled" conversion = "138-state max" if value & 0x08 else "274-state max" return f"A/D {state}, {mode} {channels}, {conversion}, {interrupt}" def _priority_bit_name(address: int, bit: int) -> str | None: for shift, source in IO_PRIORITY_FIELDS.get(address, ()): if shift <= bit <= shift + 2: return f"{source} priority bit {bit - shift}" if address in IO_PRIORITY_FIELDS and bit in (7, 3): return "reserved priority bit" return None def _dte_bit_name(address: int, bit: int) -> str | None: fields = IO_DTE_BITS.get(address) if fields is None: return None source = fields.get(bit) return f"{source} DTC enable" if source else "reserved DTE bit" def _ipr_semantics(address: int, value: int) -> str: parts: list[str] = [] for shift, source in IO_PRIORITY_FIELDS[address]: priority = (value >> shift) & 0x07 parts.append(f"{source} priority={priority}") reserved = _set_bit_numbers(value, 0x88) if reserved: parts.append(f"reserved bits {reserved} should be 0") return "; ".join(parts) def _dte_semantics(address: int, value: int) -> str: fields = IO_DTE_BITS[address] parts = [ f"{source} {'DTC enabled' if value & (1 << bit) else 'CPU interrupt'}" for bit, source in sorted(fields.items(), reverse=True) ] assigned_mask = 0 for bit in fields: assigned_mask |= 1 << bit reserved = _set_bit_numbers(value, (~assigned_mask) & 0xFF) if reserved: parts.append(f"reserved bits {reserved} should be 0") return "; ".join(parts) def _set_bit_numbers(value: int, mask: int) -> str: bits = [str(bit) for bit in range(7, -1, -1) if value & mask & (1 << bit)] return ", ".join(bits) def _sci_smr_semantics(value: int) -> str: mode = "sync" if value & 0x80 else "async" char_len = "7-bit" if value & 0x40 else "8-bit" parity = "odd parity" if value & 0x10 else "even parity" parity = parity if value & 0x20 else "no parity" stop = "2 stop" if value & 0x08 else "1 stop" clock = ["phi", "phi/4", "phi/16", "phi/64"][value & 0x03] return f"SCI {mode}, {char_len}, {parity}, {stop}, clock {clock}" def _sci_scr_semantics(value: int) -> str: enabled: list[str] = [] if value & 0x20: enabled.append("TX") if value & 0x10: enabled.append("RX") if value & 0x80: enabled.append("TXI") if value & 0x40: enabled.append("RXI/ERI") clock = "external clock" if value & 0x02 else "internal clock" if value & 0x01: clock += ", SCK output" return f"SCI enables {','.join(enabled) if enabled else 'none'}, {clock}" def _wcr_semantics(value: int) -> str: modes = ["programmable wait", "no wait states", "pin wait", "pin auto-wait"] counts = ["0 waits", "1 wait", "2 waits", "3 waits"] return f"{modes[(value >> 2) & 0x03]}, {counts[value & 0x03]}" def _wdt_semantics(value: int) -> str: if value <= 0xFF: data = value return _wdt_tcsr_data_semantics(data) password = (value >> 8) & 0xFF data = value & 0xFF if password == 0xA5: return f"TCSR password H'A5, {_wdt_tcsr_data_semantics(data)}" if password == 0x5A: return f"TCNT password H'5A, counter write {h8(data)}" return f"watchdog password {h8(password)}, data {h8(data)}" def _wdt_tcsr_data_semantics(value: int) -> str: clock = ["phi/2", "phi/32", "phi/64", "phi/128", "phi/256", "phi/512", "phi/2048", "phi/4096"][value & 0x07] mode = "watchdog NMI" if value & 0x40 else "interval IRQ0" state = "enabled" if value & 0x20 else "disabled" return f"WDT {state}, {mode}, clock {clock}" def _rstcsr_semantics(value: int) -> str: if value <= 0xFF: data = value password = None else: password = (value >> 8) & 0xFF data = value & 0xFF if password == 0xA5: return f"RSTCSR password H'A5, clear WRST with data {h8(data)}" if password == 0x5A: rstoe = "RES output enabled" if data & 0x40 else "RES output disabled" return f"RSTCSR password H'5A, {rstoe}" return "RSTCSR status/control" def _semantic_values(address: int, value: int) -> str: if address in IO_PRIORITY_FIELDS: return _ipr_semantics(address, value) if address in IO_DTE_BITS: return _dte_semantics(address, value) if address == 0xFEE8: return _adcsr_semantics(value) if address in (0xFED8, 0xFEF0): return _sci_smr_semantics(value) if address in (0xFEDA, 0xFEF2): return _sci_scr_semantics(value) if address == 0xFEFC: brle = "bus release pins enabled" if value & 0x08 else "P12/P13 are I/O" irq0 = "IRQ0 enabled" if value & 0x20 else "IRQ0 disabled" irq1 = "IRQ1 enabled" if value & 0x40 else "IRQ1 disabled" return f"{brle}, {irq0}, {irq1}" if address == 0xFEFD: enabled = [name for bit, name in ((0, "SCI2 pins"), (1, "P9 PWM"), (2, "P6 PWM"), (3, "IRQ2"), (4, "IRQ3"), (5, "IRQ4"), (6, "IRQ5")) if value & (1 << bit)] return "enabled " + ", ".join(enabled) if enabled else "alternate pin functions disabled" if address == 0xFEEC: return _wdt_semantics(value) if address == 0xFF10: return _wcr_semantics(value) if address == 0xFF11: return "on-chip RAM enabled" if value & 0x80 else "on-chip RAM disabled" if address == 0xFF12: return f"mode select bits MDS={value & 0x07}" if address == 0xFF14: return _rstcsr_semantics(value) return "" def write_comment(ea: EA, value: int | None) -> str: if ea.address is None or ea.address not in IO_REGISTERS: return "" name = IO_REGISTERS[ea.address] if value is None: return name text = f"{name} = {h16(value) if value > 0xFF else h8(value)}" fields = _bitfield_values(ea.address, value) semantic = _semantic_values(ea.address, value) details = "; ".join(part for part in (fields, semantic) if part) return f"{text} ({details})" if details else text def bit_comment(mnemonic: str, ea: EA, bit: int) -> str: if ea.address is None or ea.address not in IO_REGISTERS: return "" action = {"BSET": "set", "BCLR": "clear", "BNOT": "toggle", "BTST": "test"}.get( mnemonic.split(".")[0], "bit", ) bit_name = _bitfield_name(ea.address, bit) if bit_name: return f"{action} {bit_name} (bit {bit}) of {IO_REGISTERS[ea.address]}" return f"{action} bit {bit} of {IO_REGISTERS[ea.address]}"