#!/usr/bin/env python3
"""Tiny CPU-flag regression tests for the MN103S core.

These are intentionally narrow.  They protect the packet timer comparison seen
in GDR-8050L traces at 0x90008813..0x9000881B:

    sub d0,d2              ; 0 - 0x2000 -> 0xFFFFE000
    exthu d0               ; -> 0x0000E000, flags unchanged
    cmp 0x108A,d0          ; 0xE000 - 0x108A, BLE must be false

The goal is to separate CPU flag correctness from ATAPI/peripheral modeling.
"""
from __future__ import annotations
import sys
from mn103s_emu import MN103SEmulator, VERSION


def flags(emu: MN103SEmulator) -> str:
    c = emu.cpu
    return ''.join([
        'Z' if c.zf else 'z',
        'N' if c.nf else 'n',
        'C' if c.cf else 'c',
        'V' if c.vf else 'v',
    ])


def check(name: str, got, want) -> None:
    if got != want:
        raise AssertionError(f"{name}: got {got!r}, want {want!r}")


def main() -> int:
    emu = MN103SEmulator()
    print(f"[FLAGS] emulator={VERSION}")

    # sub d0,d2 when d2=0 and d0=0x2000.
    res = emu._sub_u32(0x00000000, 0x00002000)
    check('sub result', res, 0xFFFFE000)
    check('sub flags', flags(emu), 'zNCv')
    print(f"[OK] sub 0x00000000-0x00002000 -> 0x{res:08X} flags={flags(emu)}")

    # EXTHU is modeled in the executor and must not be used as a flag fixup.
    # Directly emulate the value effect here and assert flags stay as-is.
    before = flags(emu)
    value = res & 0xFFFF
    check('exthu value', value, 0xE000)
    check('exthu no flag change', flags(emu), before)
    print(f"[OK] exthu value -> 0x{value:04X}; flags remain {flags(emu)}")

    # cmp 0x108A,d0 with d0=0xE000 is positive, so BLE is false.
    emu._cmp_u32(0x0000E000, 0x0000108A)
    check('cmp positive flags', flags(emu), 'zncv')
    check('ble false for 0xE000 > 0x108A', (emu.cpu.zf or (emu.cpu.nf != emu.cpu.vf)), False)
    print(f"[OK] cmp 0xE000-0x108A flags={flags(emu)} ble={(emu.cpu.zf or (emu.cpu.nf != emu.cpu.vf))}")

    # FC A8/A9 abs32 byte loads reached in the post-timer GDR helper at
    # 0x800003E2/0x800003EA.  They must update D0/D1 from memory, otherwise
    # the compare loop uses stale values forever.
    emu = MN103SEmulator()
    emu.mem.write_byte(0x90000000, 0xF0)
    emu.cpu.pc = 0x800003E2
    for off, byte in enumerate([0xFC, 0xA8, 0x00, 0x00, 0x00, 0x90]):
        emu.mem.write_byte(0x800003E2 + off, byte)
    consumed = emu.extFC(0xFC)
    check('fc a8 size', consumed, 6)
    check('fc a8 d0', emu.cpu.d[0], 0xF0)
    emu.cpu.pc = 0x800003EA
    for off, byte in enumerate([0xFC, 0xA9, 0x00, 0x00, 0x00, 0x90]):
        emu.mem.write_byte(0x800003EA + off, byte)
    consumed = emu.extFC(0xFC)
    check('fc a9 size', consumed, 6)
    check('fc a9 d1', emu.cpu.d[1], 0xF0)
    print('[OK] FC A8/A9 abs32 byte loads update D0/D1 from memory')

    # If the timer delta were small/zero, BLE would loop, not exit.
    emu._cmp_u32(0x00000000, 0x0000108A)
    check('cmp negative flags', flags(emu), 'zNCv')
    check('ble true for 0 <= 0x108A', (emu.cpu.zf or (emu.cpu.nf != emu.cpu.vf)), True)
    print(f"[OK] cmp 0x0000-0x108A flags={flags(emu)} ble={(emu.cpu.zf or (emu.cpu.nf != emu.cpu.vf))}")

    print('[OK] MN103S flag regression tests passed')
    return 0


if __name__ == '__main__':
    raise SystemExit(main())
