Data flow improvements in pseudo code generator
This commit is contained in:
123
tests/test_symbols.py
Normal file
123
tests/test_symbols.py
Normal 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()
|
||||
Reference in New Issue
Block a user