1
0

EMualtor adjustments

This commit is contained in:
Aiden
2026-05-25 20:42:45 +10:00
parent d2e7609bbf
commit 3ab79648ff
17 changed files with 3047 additions and 83 deletions

View File

@@ -41,6 +41,20 @@ def fixture_payload() -> dict[str, object]:
ins(0x3FEF, "TST.B @H'F9C5", references=[0xF9C5]),
ins(0x3FF5, "CLR.B @H'F9B5", references=[0xF9B5]),
ins(0x3FF9, "CLR.B @H'F9B0", references=[0xF9B0]),
ins(0x4046, "TST.B @H'F9C4", references=[0xF9C4]),
ins(0x404A, "BNE loc_4058", targets=[0x4058]),
ins(0x404C, "BTST.B #7, @H'FAA5", references=[0xFAA5]),
ins(0x4050, "BEQ loc_4059", targets=[0x4059]),
ins(0x4052, "TST.B @H'F9C3", references=[0xF9C3]),
ins(0x4056, "BEQ loc_4059", targets=[0x4059]),
ins(0x4058, "RTS"),
ins(0x4059, "MOV:G.B @H'F9B0, R2", references=[0xF9B0]),
ins(0x405F, "CMP:G.B @H'F9B5, R2", references=[0xF9B5]),
ins(0x4063, "BNE loc_4074", targets=[0x4074]),
ins(0x4067, "MOV:G.W #H'00, @(-H'0790,R2)"),
ins(0x406C, "ADD:Q.B #1, @H'F9B0", references=[0xF9B0]),
ins(0x4070, "BCLR.B #7, @H'F9B0", references=[0xF9B0]),
ins(0x40E0, "MOV:G.B #H'14, @H'F9C4", references=[0xF9C4]),
ins(0xBAF2, "MOV:G.B @H'F9B5, R1", references=[0xF9B5]),
ins(0xBAF8, "CMP:G.B @H'F9B0, R1", references=[0xF9B0]),
ins(0xBAFC, "BNE loc_BB00", targets=[0xBB00]),
@@ -67,6 +81,7 @@ def fixture_payload() -> dict[str, object]:
ins(0xBEA5, "AND.B @H'FAA3, R0", references=[0xFAA3]),
ins(0xBEA9, "MOV:G.B R0, @H'FAA3", references=[0xFAA3]),
ins(0xBEAF, "CLR.B @H'FAA2", references=[0xFAA2]),
ins(0xBA31, "MOV:G.B #H'07, @H'F9C4", references=[0xF9C4]),
ins(0xBEB5, "TST.W @H'F9C6", references=[0xF9C6]),
ins(0xBEBB, "TST.B @H'F9C8", references=[0xF9C8]),
ins(0xBEC5, "MOV:G.W #H'01F4, @H'F9C6", references=[0xF9C6]),
@@ -83,9 +98,15 @@ def fixture_payload() -> dict[str, object]:
ins(0xBF02, "TST.W @H'F9C6", references=[0xF9C6]),
ins(0xBF06, "BEQ loc_BF0C", targets=[0xBF0C]),
ins(0xBF08, "ADD:Q.W #-1, @H'F9C6", references=[0xF9C6]),
ins(0xBF23, "BCLR.B #5, @FRT2_TCSR"),
ins(0xBF27, "TST.B @H'F9C4", references=[0xF9C4]),
ins(0xBF2D, "ADD:Q.B #-1, @H'F9C4", references=[0xF9C4]),
]
return {
"vectors": [{"address": 0x0062, "name": "frt1_ocia", "target": 0xBEEA, "target_label": "vec_frt1_ocia_BEEA"}],
"vectors": [
{"address": 0x0062, "name": "frt1_ocia", "target": 0xBEEA, "target_label": "vec_frt1_ocia_BEEA"},
{"address": 0x006A, "name": "frt2_ocia", "target": 0xBF23, "target_label": "vec_frt2_ocia_BF23"},
],
"call_graph": {"nodes": [{"start": 0x3FD3, "label": "loc_3FD3"}, {"start": 0xBAF2, "label": "loc_BAF2"}]},
"instructions": rows,
}
@@ -119,6 +140,17 @@ class SerialGateTest(unittest.TestCase):
self.assertIn("secondary delay", roles[0xF9C1]["role"])
self.assertIn("periodic report/heartbeat", roles[0xF9C6]["role"])
def test_json_analysis_includes_frt2_idle_heartbeat_gate(self):
analysis = analyze_serial_gate(fixture_payload())
gate = analysis["evidence"]["idle_heartbeat_gate_loc_4046"]
self.assertTrue(gate["present"])
self.assertEqual(gate["timer"]["handler_address_hex"], "H'BF23")
self.assertEqual(gate["post_tx_reload_value_hex"], "H'07")
self.assertIn("0.7s", gate["summary"])
roles = {role["address"]: role for role in gate["candidate_timer_roles"]}
self.assertIn("heartbeat", roles[0xF9C4]["role"])
def test_summarizes_key_state_readers_and_writers(self):
analysis = analyze_serial_gate(fixture_payload())
accesses = {entry["address"]: entry for entry in analysis["state_accesses"]}
@@ -126,6 +158,7 @@ class SerialGateTest(unittest.TestCase):
self.assertGreaterEqual(accesses[0xF9B5]["read_count"], 1)
self.assertGreaterEqual(accesses[0xF9B5]["read_write_count"], 1)
self.assertGreaterEqual(accesses[0xF9C1]["read_write_count"], 1)
self.assertGreaterEqual(accesses[0xF9C4]["read_write_count"], 1)
self.assertGreaterEqual(accesses[0xFAA3]["write_count"], 1)
self.assertIn("sample_accesses", accesses[0xFAA2])
@@ -145,6 +178,14 @@ class SerialGateTest(unittest.TestCase):
self.assertIn("H'F9C1: candidate secondary delay countdown", text)
self.assertIn("H'F9C6: candidate periodic report/heartbeat countdown", text)
def test_text_report_mentions_frt2_idle_heartbeat_gate(self):
text = format_text_report(analyze_serial_gate(fixture_payload()))
self.assertIn("loc_4046 idle heartbeat/report gate: present", text)
self.assertIn("FRT2 OCIA", text)
self.assertIn("H'F9C4: candidate idle heartbeat/report gate countdown", text)
self.assertIn("observed period ~= 700ms", text)
def test_cli_json_output_and_out_file(self):
with tempfile.TemporaryDirectory() as tmp:
input_path = Path(tmp) / "rom.json"