121 lines
4.4 KiB
Python
121 lines
4.4 KiB
Python
import io
|
|
import json
|
|
import tempfile
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
from h8536.eeprom_layout import (
|
|
analyze_eeprom_layout,
|
|
format_text_report,
|
|
main,
|
|
write_eeprom_layout,
|
|
)
|
|
|
|
|
|
def reference(address: int) -> dict:
|
|
return {"address": address}
|
|
|
|
|
|
def instruction(address: int, mnemonic: str, operands: str = "", refs: list[int] | None = None) -> dict:
|
|
return {
|
|
"address": address,
|
|
"mnemonic": mnemonic,
|
|
"operands": operands,
|
|
"text": f"{mnemonic} {operands}".strip(),
|
|
"references": [reference(item) for item in (refs or [])],
|
|
"targets": [],
|
|
}
|
|
|
|
|
|
def payload() -> dict:
|
|
return {
|
|
"instructions": [
|
|
instruction(0x410C, "MOV:G.W", "R5, @(-H'0C00,R0)"),
|
|
instruction(0x41E8, "MOV:G.W", "R5, @(-H'0850,R1)"),
|
|
instruction(0x40FA, "CMP:G.W", "#H'6B6F, @H'F402", [0xF402]),
|
|
instruction(0xBD3D, "MOV:G.B", "@(-H'3A9B,R4), R1"),
|
|
instruction(0xBD45, "MOV:G.W", "R0, @(-H'0C00,R1)"),
|
|
instruction(0xBD49, "BTST.B", "#7, @H'F76E", [0xF76E]),
|
|
],
|
|
"call_graph": {
|
|
"nodes": [
|
|
{"start": 0x4000, "end": 0x4216, "label": "loc_4000"},
|
|
{"start": 0xBD0E, "end": 0xBD67, "label": "loc_BD0E"},
|
|
],
|
|
},
|
|
}
|
|
|
|
|
|
def rom_bytes() -> bytes:
|
|
rom = bytearray([0xFF] * 0xCB00)
|
|
rom[0xC564 : 0xC564 + 0x400] = b"\x00" * 0x400
|
|
rom[0xC564 + 0x015 * 2 : 0xC564 + 0x015 * 2 + 2] = b"\x40\xAA"
|
|
rom[0xC966:0xC968] = b"\x6B\x6F"
|
|
rom[0xC968:0xC96A] = b"\xFE\x00"
|
|
rom[0xCA0E:0xCA10] = b"\x80\x00"
|
|
return bytes(rom)
|
|
|
|
|
|
class EepromLayoutTest(unittest.TestCase):
|
|
def test_analysis_extracts_factory_defaults_records_and_selector_mapping(self):
|
|
with tempfile.TemporaryDirectory() as tmp:
|
|
rom_path = Path(tmp) / "rom.bin"
|
|
rom_path.write_bytes(rom_bytes())
|
|
|
|
analysis = analyze_eeprom_layout(payload(), rom_path=rom_path)
|
|
|
|
self.assertEqual(analysis["kind"], "eeprom_layout")
|
|
self.assertEqual(analysis["factory_defaults"]["entries"][1]["factory_word_hex"], "0x6B6F")
|
|
self.assertEqual(analysis["persistent_records"][3]["ram_base_hex"], "H'F7C8")
|
|
self.assertEqual(analysis["persistent_records"][3]["eeprom_base_hex"], "0x300")
|
|
mapped = analysis["serial_persistence_mapping"]["entries"][0]
|
|
self.assertEqual(mapped["selector_hex"], "0x015")
|
|
self.assertEqual(mapped["shadow_address_hex"], "H'F4AA")
|
|
self.assertEqual(mapped["eeprom_word_offset_hex"], "0xAA")
|
|
self.assertEqual(mapped["factory_word_hex"], "0x8000")
|
|
|
|
def test_text_report_mentions_core_layout(self):
|
|
with tempfile.TemporaryDirectory() as tmp:
|
|
rom_path = Path(tmp) / "rom.bin"
|
|
rom_path.write_bytes(rom_bytes())
|
|
analysis = analyze_eeprom_layout(payload(), rom_path=rom_path)
|
|
|
|
text = format_text_report(analysis)
|
|
|
|
self.assertIn("Persistent 8-Byte Records", text)
|
|
self.assertIn("selector 0x015", text)
|
|
self.assertIn("F76E", text)
|
|
|
|
def test_write_json_output(self):
|
|
with tempfile.TemporaryDirectory() as tmp:
|
|
input_path = Path(tmp) / "rom.json"
|
|
output_path = Path(tmp) / "eeprom.json"
|
|
rom_path = Path(tmp) / "rom.bin"
|
|
input_path.write_text(json.dumps(payload()), encoding="utf-8")
|
|
rom_path.write_bytes(rom_bytes())
|
|
|
|
write_eeprom_layout(input_path, output_path, rom_path=rom_path, as_json=True)
|
|
|
|
written = json.loads(output_path.read_text(encoding="utf-8"))
|
|
self.assertEqual(written["kind"], "eeprom_layout")
|
|
self.assertEqual(written["summary"]["persistent_record_count"], 16)
|
|
|
|
def test_cli_writes_text_report(self):
|
|
with tempfile.TemporaryDirectory() as tmp:
|
|
input_path = Path(tmp) / "rom.json"
|
|
output_path = Path(tmp) / "eeprom.txt"
|
|
rom_path = Path(tmp) / "rom.bin"
|
|
input_path.write_text(json.dumps(payload()), encoding="utf-8")
|
|
rom_path.write_bytes(rom_bytes())
|
|
|
|
stdout = io.StringIO()
|
|
rc = main([str(input_path), "--rom", str(rom_path), "--out", str(output_path)], stdout=stdout)
|
|
|
|
self.assertEqual(rc, 0)
|
|
self.assertIn("wrote", stdout.getvalue())
|
|
self.assertIn("EEPROM Layout Report", output_path.read_text(encoding="utf-8"))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|