1
0

Data flow improvements in pseudo code generator

This commit is contained in:
Aiden
2026-05-25 14:40:55 +10:00
parent 80819448cf
commit 1d7f00e59c
16 changed files with 105891 additions and 5141 deletions

123
tests/test_symbols.py Normal file
View File

@@ -0,0 +1,123 @@
import unittest
from h8536.model import Instruction
from h8536.symbols import discover_symbols, instruction_accesses, symbol_for_address
def ins(address, mnemonic, operands="", references=None):
return Instruction(
address,
b"\x00",
mnemonic,
operands,
references=list(references or []),
)
class SymbolDiscoveryTest(unittest.TestCase):
def test_discovers_ram_symbol_counts_direction_and_widths(self):
instructions = {
0x1000: ins(0x1000, "MOV:G.B", "#H'12, @H'F680", [0xF680]),
0x1004: ins(0x1004, "CMP:G.B", "#H'01, @H'F680", [0xF680]),
0x1008: ins(0x1008, "ADD:Q.W", "#1, @H'F680", [0xF680]),
}
analysis = discover_symbols(instructions)
symbols = analysis["symbols"]
self.assertEqual(len(symbols), 1)
symbol = symbols[0]
self.assertEqual(symbol["address"], 0xF680)
self.assertEqual(symbol["name"], "ram_F680")
self.assertEqual(symbol["region"], "on_chip_ram")
self.assertEqual(symbol["kind"], "ram")
self.assertEqual(symbol["access_count"], 3)
self.assertEqual(symbol["read_count"], 2)
self.assertEqual(symbol["write_count"], 2)
self.assertEqual(symbol["unknown_count"], 0)
self.assertEqual(symbol["width_hints"], ["byte", "word"])
self.assertEqual(symbol["width"], "mixed")
self.assertEqual(symbol["first_access"], 0x1000)
self.assertEqual(symbol["last_access"], 0x1008)
self.assertEqual(symbol_for_address(analysis, 0xF680), "ram_F680")
def test_names_program_or_external_memory_and_excludes_registers_by_default(self):
instructions = [
ins(0x2000, "MOV:G.W", "@H'1234, R1", [0x1234]),
ins(0x2004, "MOV:G.B", "#H'80, @RAMCR", [0xFF11]),
]
analysis = discover_symbols(instructions)
self.assertEqual([symbol["name"] for symbol in analysis["symbols"]], ["mem_1234"])
symbol = analysis["symbols"][0]
self.assertEqual(symbol["region"], "program_or_external")
self.assertEqual(symbol["kind"], "memory")
self.assertEqual(symbol["read_count"], 1)
self.assertIsNone(symbol_for_address(analysis, 0xFF11))
def test_can_include_io_register_symbols_when_requested(self):
instructions = [
ins(0x2004, "MOV:G.B", "#H'80, @RAMCR", [0xFF11]),
]
analysis = discover_symbols(instructions, include_registers=True)
self.assertEqual(len(analysis["symbols"]), 1)
symbol = analysis["symbols"][0]
self.assertEqual(symbol["address"], 0xFF11)
self.assertEqual(symbol["name"], "RAMCR")
self.assertEqual(symbol["region"], "register_field")
self.assertEqual(symbol["kind"], "register")
self.assertEqual(symbol["write_count"], 1)
def test_bit_and_clear_operations_use_conservative_directions(self):
instructions = [
ins(0x3000, "BSET.B", "#4, @H'F690", [0xF690]),
ins(0x3002, "BCLR.B", "#4, @H'F690", [0xF690]),
ins(0x3004, "TST.B", "@H'F690", [0xF690]),
ins(0x3006, "CLR.B", "@H'F690", [0xF690]),
]
analysis = discover_symbols(instructions)
symbol = analysis["symbols"][0]
self.assertEqual(symbol["read_count"], 3)
self.assertEqual(symbol["write_count"], 3)
self.assertEqual(
[access["direction"] for access in symbol["accesses"]],
["read_write", "read_write", "read", "write"],
)
def test_optional_pointer_table_candidates_add_xrefs_without_io_pollution(self):
instructions = [
ins(0x4000, "MOV:G.B", "@H'F680, R0", [0xF680]),
]
data_candidates = {
"pointer_tables": [
{
"address": 0x0200,
"targets": [0xF680, 0x1234, 0xFF11],
},
],
}
analysis = discover_symbols(instructions, data_candidates=data_candidates)
by_name = {symbol["name"]: symbol for symbol in analysis["symbols"]}
self.assertEqual(by_name["ram_F680"]["xref_count"], 1)
self.assertEqual(by_name["mem_1234"]["access_count"], 0)
self.assertEqual(by_name["mem_1234"]["xref_count"], 1)
self.assertNotIn("RAMCR", by_name)
def test_instruction_accesses_handles_comma_inside_displacement_operand(self):
access = instruction_accesses(
ins(0x5000, "MOV:G.B", "@(H'0010,R1), @H'F682", [0xF682]),
)
self.assertEqual(access[0]["direction"], "write")
self.assertEqual(access[0]["operand"], "@H'F682")
if __name__ == "__main__":
unittest.main()