serial improvements
This commit is contained in:
@@ -97,6 +97,23 @@ def candidate_payload() -> dict:
|
||||
}
|
||||
|
||||
|
||||
def semantic_payload() -> dict:
|
||||
payload = candidate_payload()
|
||||
payload["instructions"] = [
|
||||
{"address": 0xBC08, "mnemonic": "MOV:G.B", "operands": "@H'F860, R0", "references": [{"address": 0xF860}], "targets": []},
|
||||
{"address": 0xBC0C, "mnemonic": "AND.B", "operands": "#H'07, R0", "references": [], "targets": []},
|
||||
{"address": 0xBC20, "mnemonic": "CMP:E.B", "operands": "#H'00, R0", "references": [], "targets": []},
|
||||
{"address": 0xBC22, "mnemonic": "BEQ", "operands": "loc_BC69", "references": [], "targets": [0xBC69]},
|
||||
{"address": 0xBC24, "mnemonic": "CMP:E.B", "operands": "#H'01, R0", "references": [], "targets": []},
|
||||
{"address": 0xBC26, "mnemonic": "BEQ", "operands": "loc_BCD7", "references": [], "targets": [0xBCD7]},
|
||||
{"address": 0xBCB0, "mnemonic": "MOV:G.B", "operands": "#H'04, @H'F850", "references": [{"address": 0xF850}], "targets": []},
|
||||
{"address": 0xBCB5, "mnemonic": "MOV:G.B", "operands": "@H'F861, R0", "references": [{"address": 0xF861}], "targets": []},
|
||||
{"address": 0xBCB9, "mnemonic": "MOV:G.B", "operands": "R0, @H'F851", "references": [{"address": 0xF851}], "targets": []},
|
||||
{"address": 0xBCCD, "mnemonic": "BSR", "operands": "loc_BA26", "references": [], "targets": [0xBA26]},
|
||||
]
|
||||
return payload
|
||||
|
||||
|
||||
class SerialPseudocodeTest(unittest.TestCase):
|
||||
def test_generates_focused_tx_and_rx_candidate_paths(self):
|
||||
text = generate_serial_pseudocode(candidate_payload(), source_name="rom.json")
|
||||
@@ -117,6 +134,17 @@ class SerialPseudocodeTest(unittest.TestCase):
|
||||
self.assertIn("return sci1_process_rx_candidate_frame();", text)
|
||||
self.assertIn("rx_xor_checksum_validation: H'BBD6, H'BBEC", text)
|
||||
|
||||
def test_generates_candidate_protocol_semantics_switch(self):
|
||||
text = generate_serial_pseudocode(semantic_payload())
|
||||
|
||||
self.assertIn("Candidate Protocol Semantics", text)
|
||||
self.assertIn("byte0: op_flags", text)
|
||||
self.assertIn("dispatch: command_low3 = RX_FRAME(0) & 0x07", text)
|
||||
self.assertIn("case 0x00u:", text)
|
||||
self.assertIn("candidate_set_value_acked(logical_index, value);", text)
|
||||
self.assertIn("case 0x01u:", text)
|
||||
self.assertIn("candidate_read_value(logical_index, value);", text)
|
||||
|
||||
def test_tx_only_option_omits_rx_functions(self):
|
||||
text = generate_serial_pseudocode(
|
||||
candidate_payload(),
|
||||
|
||||
160
tests/test_serial_semantics.py
Normal file
160
tests/test_serial_semantics.py
Normal file
@@ -0,0 +1,160 @@
|
||||
import unittest
|
||||
|
||||
from h8536.serial_semantics import analyze_serial_semantics
|
||||
|
||||
|
||||
def reference(address: int) -> dict:
|
||||
return {"address": address}
|
||||
|
||||
|
||||
def instruction(
|
||||
address: int,
|
||||
mnemonic: str,
|
||||
operands: str = "",
|
||||
references: list[int] | None = None,
|
||||
targets: list[int] | None = None,
|
||||
) -> dict:
|
||||
return {
|
||||
"address": address,
|
||||
"mnemonic": mnemonic,
|
||||
"operands": operands,
|
||||
"references": [reference(item) for item in (references or [])],
|
||||
"targets": targets or [],
|
||||
}
|
||||
|
||||
|
||||
def base_payload(instructions: list[dict]) -> dict:
|
||||
return {
|
||||
"serial_reconstruction": {
|
||||
"candidates": [
|
||||
{
|
||||
"kind": "candidate_sci1_rx_frame",
|
||||
"channel": "SCI1",
|
||||
"frame_length": 6,
|
||||
"validation_buffer_start": 0xF860,
|
||||
"validation_buffer_end": 0xF865,
|
||||
"checksum_address": 0xF865,
|
||||
"checksum_seed": 0x5A,
|
||||
"confidence": "high",
|
||||
},
|
||||
{
|
||||
"kind": "candidate_sci1_tx_frame",
|
||||
"channel": "SCI1",
|
||||
"frame_length": 6,
|
||||
"buffer_start": 0xF850,
|
||||
"buffer_end": 0xF855,
|
||||
"checksum_address": 0xF855,
|
||||
"checksum_seed": 0x5A,
|
||||
"confidence": "high",
|
||||
},
|
||||
],
|
||||
},
|
||||
"instructions": instructions,
|
||||
}
|
||||
|
||||
|
||||
def only_semantics(testcase: unittest.TestCase, payload: dict) -> dict:
|
||||
analysis = analyze_serial_semantics(payload)
|
||||
testcase.assertEqual(analysis["kind"], "serial_semantics")
|
||||
testcase.assertEqual(len(analysis["protocol_semantics"]), 1)
|
||||
return analysis["protocol_semantics"][0]
|
||||
|
||||
|
||||
class SerialSemanticsTest(unittest.TestCase):
|
||||
def test_detects_low_three_bit_command_dispatch(self):
|
||||
payload = base_payload(
|
||||
[
|
||||
instruction(0xBA80, "MOV:G.B", "@H'F860, R0", [0xF860]),
|
||||
instruction(0xBA84, "AND.B", "#H'07, R0"),
|
||||
instruction(0xBA88, "CMP:E.B", "#H'00, R0"),
|
||||
instruction(0xBA8C, "BEQ", "loc_BAA0", targets=[0xBAA0]),
|
||||
instruction(0xBA90, "CMP:E.B", "#H'02, R0"),
|
||||
instruction(0xBA94, "BEQ", "loc_BAC0", targets=[0xBAC0]),
|
||||
instruction(0xBA98, "CMP:E.B", "#H'07, R0"),
|
||||
instruction(0xBA9C, "BEQ", "loc_BAE0", targets=[0xBAE0]),
|
||||
]
|
||||
)
|
||||
|
||||
semantics = only_semantics(self, payload)
|
||||
|
||||
dispatch = semantics["command_dispatch"]
|
||||
self.assertEqual(dispatch["source_address"], 0xF860)
|
||||
self.assertEqual(dispatch["source_field"], "byte0")
|
||||
self.assertEqual(dispatch["mask"], 0x07)
|
||||
self.assertEqual(dispatch["field"], "command_low3")
|
||||
self.assertEqual(
|
||||
{(case["value"], case["target"]) for case in dispatch["cases"]},
|
||||
{(0x00, 0xBAA0), (0x02, 0xBAC0), (0x07, 0xBAE0)},
|
||||
)
|
||||
self.assertIn(0xBA80, dispatch["evidence_addresses"])
|
||||
self.assertIn(0xBA84, dispatch["evidence_addresses"])
|
||||
|
||||
def test_labels_likely_rx_fields_from_validation_buffer_offsets(self):
|
||||
payload = base_payload(
|
||||
[
|
||||
instruction(0xBB00, "MOV:G.B", "@H'F860, R0", [0xF860]),
|
||||
instruction(0xBB04, "AND.B", "#H'07, R0"),
|
||||
instruction(0xBB08, "MOV:G.W", "@H'F861, R1", [0xF861]),
|
||||
instruction(0xBB0C, "MOV:G.W", "@H'F863, R2", [0xF863]),
|
||||
]
|
||||
)
|
||||
|
||||
semantics = only_semantics(self, payload)
|
||||
|
||||
fields = {field["offset"]: field for field in semantics["rx_fields"]}
|
||||
self.assertEqual(fields[0]["name"], "command_low3")
|
||||
self.assertEqual(fields[0]["address"], 0xF860)
|
||||
self.assertEqual(fields[0]["mask"], 0x07)
|
||||
self.assertEqual(fields[1]["name"], "likely_id_or_index")
|
||||
self.assertEqual(fields[2]["name"], "likely_id_or_index")
|
||||
self.assertEqual(fields[3]["name"], "likely_value")
|
||||
self.assertEqual(fields[4]["name"], "likely_value")
|
||||
self.assertIn("candidate", fields[1]["confidence"])
|
||||
self.assertIn("candidate", fields[3]["confidence"])
|
||||
|
||||
def test_detects_response_builder_before_serial_send_call(self):
|
||||
payload = base_payload(
|
||||
[
|
||||
instruction(0xBC00, "MOV:G.B", "@H'F860, R0", [0xF860]),
|
||||
instruction(0xBC04, "MOV:G.B", "R0, @H'F850", [0xF850]),
|
||||
instruction(0xBC08, "MOV:G.B", "@H'F861, R1", [0xF861]),
|
||||
instruction(0xBC0C, "MOV:G.B", "R1, @H'F851", [0xF851]),
|
||||
instruction(0xBC10, "MOV:G.B", "@H'F862, R2", [0xF862]),
|
||||
instruction(0xBC14, "MOV:G.B", "R2, @H'F852", [0xF852]),
|
||||
instruction(0xBC18, "MOV:G.B", "#H'00, @H'F853", [0xF853]),
|
||||
instruction(0xBC1C, "MOV:G.B", "#H'01, @H'F854", [0xF854]),
|
||||
instruction(0xBC20, "BSR", "loc_BA26", targets=[0xBA26]),
|
||||
]
|
||||
)
|
||||
|
||||
semantics = only_semantics(self, payload)
|
||||
|
||||
response = semantics["response_builders"][0]
|
||||
self.assertEqual(response["buffer_start"], 0xF850)
|
||||
self.assertEqual(response["buffer_end"], 0xF854)
|
||||
self.assertEqual(response["send_call_target"], 0xBA26)
|
||||
self.assertEqual(response["call_address"], 0xBC20)
|
||||
self.assertEqual(
|
||||
[write["address"] for write in response["writes"]],
|
||||
[0xF850, 0xF851, 0xF852, 0xF853, 0xF854],
|
||||
)
|
||||
|
||||
def test_missing_serial_reconstruction_candidates_emit_no_protocol_semantics(self):
|
||||
payload = {
|
||||
"serial_reconstruction": {"candidates": []},
|
||||
"instructions": [
|
||||
instruction(0xBA80, "MOV:G.B", "@H'F860, R0", [0xF860]),
|
||||
instruction(0xBA84, "AND.B", "#H'07, R0"),
|
||||
instruction(0xBA88, "CMP:E.B", "#H'00, R0"),
|
||||
instruction(0xBA8C, "BEQ", "loc_BAA0", targets=[0xBAA0]),
|
||||
],
|
||||
}
|
||||
|
||||
analysis = analyze_serial_semantics(payload)
|
||||
|
||||
self.assertEqual(analysis["kind"], "serial_semantics")
|
||||
self.assertEqual(analysis["protocol_semantics"], [])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user