DTC and SCI improvements
This commit is contained in:
103
tests/test_dtc.py
Normal file
103
tests/test_dtc.py
Normal file
@@ -0,0 +1,103 @@
|
||||
import json
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
from h8536.render import format_listing, write_json
|
||||
from h8536.rom import Rom
|
||||
from h8536.vectors import read_dtc_vectors_min
|
||||
|
||||
|
||||
def _manual_sci1_rxi_rom() -> Rom:
|
||||
data = bytearray([0xFF] * 0xFB88)
|
||||
data[0x00A2:0x00A4] = bytes([0xFB, 0x80])
|
||||
data[0xFB80:0xFB88] = bytes(
|
||||
[
|
||||
0x20,
|
||||
0x00, # DTMR: byte transfer, destination increments
|
||||
0xFE,
|
||||
0xDD, # DTSR: SCI1_RDR
|
||||
0xFC,
|
||||
0x00, # DTDR: receive buffer
|
||||
0x00,
|
||||
0x80, # DTCR: 128 transfers
|
||||
],
|
||||
)
|
||||
return Rom(bytes(data))
|
||||
|
||||
|
||||
class DtcDecodeTest(unittest.TestCase):
|
||||
def test_decodes_manual_sci1_receive_register_information(self):
|
||||
vectors = read_dtc_vectors_min(_manual_sci1_rxi_rom())
|
||||
entry = vectors[0x00A2]
|
||||
info = entry["register_info"]
|
||||
|
||||
self.assertTrue(info["valid"])
|
||||
self.assertEqual(entry["source"], "sci1_rxi")
|
||||
self.assertEqual(info["dtmr"], 0x2000)
|
||||
self.assertEqual(info["mode"]["size"], "byte")
|
||||
self.assertFalse(info["mode"]["source_increment"])
|
||||
self.assertTrue(info["mode"]["destination_increment"])
|
||||
self.assertEqual(info["source"]["address"], 0xFEDD)
|
||||
self.assertEqual(info["source"]["name"], "SCI1_RDR")
|
||||
self.assertEqual(info["destination"]["address"], 0xFC00)
|
||||
self.assertEqual(info["destination"]["region"], "on_chip_ram")
|
||||
self.assertEqual(info["count"]["transfers"], 128)
|
||||
self.assertEqual(info["count"]["bytes"], 128)
|
||||
|
||||
def test_invalid_register_information_pointer_is_reported_conservatively(self):
|
||||
data = bytearray([0xFF] * 0x0200)
|
||||
data[0x00A2:0x00A4] = bytes([0xFB, 0x80])
|
||||
|
||||
vectors = read_dtc_vectors_min(Rom(bytes(data)))
|
||||
info = vectors[0x00A2]["register_info"]
|
||||
|
||||
self.assertFalse(info["valid"])
|
||||
self.assertIn("outside ROM image", info["error"])
|
||||
|
||||
def test_zero_count_represents_65536_transfers(self):
|
||||
data = bytearray([0xFF] * 0x0200)
|
||||
data[0x00C0:0x00C2] = bytes([0x01, 0x00])
|
||||
data[0x0100:0x0108] = bytes([0xC0, 0x00, 0x01, 0x20, 0xFE, 0x80, 0x00, 0x00])
|
||||
|
||||
info = read_dtc_vectors_min(Rom(bytes(data)))[0x00C0]["register_info"]
|
||||
|
||||
self.assertEqual(info["mode"]["size"], "word")
|
||||
self.assertEqual(info["mode"]["source_increment_step"], 2)
|
||||
self.assertEqual(info["count"]["transfers"], 65536)
|
||||
self.assertEqual(info["count"]["bytes"], 131072)
|
||||
self.assertTrue(info["count"]["zero_means_65536"])
|
||||
|
||||
def test_listing_and_json_include_decoded_register_information(self):
|
||||
rom = _manual_sci1_rxi_rom()
|
||||
dtc_vectors = read_dtc_vectors_min(rom)
|
||||
|
||||
listing = format_listing(
|
||||
Path("rom.bin"),
|
||||
rom,
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
"min",
|
||||
traced=True,
|
||||
dtc_vectors=dtc_vectors,
|
||||
)
|
||||
|
||||
self.assertIn("; DTC Register Information", listing)
|
||||
self.assertIn("sci1_rxi", listing)
|
||||
self.assertIn("byte x128", listing)
|
||||
self.assertIn("SCI1_RDR (H'FEDD) -> H'FC00", listing)
|
||||
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
path = Path(tmpdir) / "out.json"
|
||||
write_json(path, {}, {}, {}, dtc_vectors=dtc_vectors)
|
||||
payload = json.loads(path.read_text(encoding="utf-8"))
|
||||
|
||||
json_info = payload["dtc_vectors"][0]["register_info"]
|
||||
self.assertEqual(json_info["mode"]["size"], "byte")
|
||||
self.assertEqual(json_info["source"]["name"], "SCI1_RDR")
|
||||
self.assertEqual(json_info["count"]["transfers"], 128)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
50
tests/test_interrupt_annotations.py
Normal file
50
tests/test_interrupt_annotations.py
Normal file
@@ -0,0 +1,50 @@
|
||||
import unittest
|
||||
|
||||
from h8536.decoder import H8536Decoder
|
||||
from h8536.rom import Rom
|
||||
|
||||
|
||||
def decode(data: list[int]):
|
||||
return H8536Decoder(Rom(bytes(data), base=0)).decode(0)
|
||||
|
||||
|
||||
def mov_b_immediate_to_abs16(address: int, value: int):
|
||||
return decode([0x15, (address >> 8) & 0xFF, address & 0xFF, 0x06, value])
|
||||
|
||||
|
||||
def bit_op_abs16(address: int, op: int):
|
||||
return decode([0x15, (address >> 8) & 0xFF, address & 0xFF, op])
|
||||
|
||||
|
||||
class InterruptAnnotationTest(unittest.TestCase):
|
||||
def test_ipra_write_decodes_irq_priority_levels(self):
|
||||
instruction = mov_b_immediate_to_abs16(0xFF00, 0x75)
|
||||
|
||||
self.assertEqual(instruction.text, "MOV:G.B #H'75, @IPRA")
|
||||
self.assertEqual(instruction.comment, "IPRA = H'75 (irq0 priority=7; irq1 priority=5)")
|
||||
|
||||
def test_iprf_write_decodes_ad_priority_and_reserved_bits(self):
|
||||
instruction = mov_b_immediate_to_abs16(0xFF05, 0xF8)
|
||||
|
||||
self.assertEqual(instruction.text, "MOV:G.B #H'F8, @IPRF")
|
||||
self.assertEqual(instruction.comment, "IPRF = H'F8 (A/D priority=7; reserved bits 7, 3 should be 0)")
|
||||
|
||||
def test_dtee_write_decodes_dtc_routing_by_interrupt_source(self):
|
||||
instruction = mov_b_immediate_to_abs16(0xFF0C, 0x24)
|
||||
|
||||
self.assertEqual(instruction.text, "MOV:G.B #H'24, @DTEE")
|
||||
self.assertEqual(
|
||||
instruction.comment,
|
||||
"DTEE = H'24 (SCI1 TXI CPU interrupt; SCI1 RXI DTC enabled; "
|
||||
"SCI2 TXI DTC enabled; SCI2 RXI CPU interrupt)",
|
||||
)
|
||||
|
||||
def test_dtea_bit_set_names_dtc_enable_source(self):
|
||||
instruction = bit_op_abs16(0xFF08, 0xC4)
|
||||
|
||||
self.assertEqual(instruction.text, "BSET.B #4, @DTEA")
|
||||
self.assertEqual(instruction.comment, "set irq0 DTC enable (bit 4) of DTEA")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
90
tests/test_peripheral_access.py
Normal file
90
tests/test_peripheral_access.py
Normal file
@@ -0,0 +1,90 @@
|
||||
import json
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
from h8536.model import Instruction
|
||||
from h8536.peripheral_access import analyze_peripheral_access, peripheral_comment_for_instruction
|
||||
from h8536.render import write_json
|
||||
from h8536.tables import IO_REGISTERS
|
||||
|
||||
|
||||
class PeripheralAccessTest(unittest.TestCase):
|
||||
def test_frt1_manual_register_map_has_full_16_bit_pairs(self):
|
||||
self.assertEqual(IO_REGISTERS[0xFE94], "FRT1_OCRA_H")
|
||||
self.assertEqual(IO_REGISTERS[0xFE95], "FRT1_OCRA_L")
|
||||
self.assertEqual(IO_REGISTERS[0xFE98], "FRT1_ICR_H")
|
||||
|
||||
def test_frt_word_access_is_marked_as_temp_safe(self):
|
||||
instructions = {
|
||||
0x1000: Instruction(
|
||||
0x1000,
|
||||
bytes.fromhex("1DFEA2051234"),
|
||||
"MOV:G.W",
|
||||
"#H'1234, @FRT2_FRC_H",
|
||||
references=[0xFEA2],
|
||||
),
|
||||
}
|
||||
|
||||
analysis = analyze_peripheral_access(instructions)
|
||||
|
||||
self.assertIn("TEMP byte-order hazard avoided", peripheral_comment_for_instruction(analysis, 0x1000))
|
||||
self.assertEqual(analysis["warnings"], [])
|
||||
|
||||
def test_low_byte_read_before_high_byte_warns(self):
|
||||
instructions = {
|
||||
0x1000: Instruction(
|
||||
0x1000,
|
||||
bytes.fromhex("15FEE105"),
|
||||
"MOV:G.B",
|
||||
"@ADDRA_L, R0",
|
||||
references=[0xFEE1],
|
||||
),
|
||||
}
|
||||
|
||||
analysis = analyze_peripheral_access(instructions)
|
||||
|
||||
self.assertEqual(len(analysis["warnings"]), 1)
|
||||
self.assertIn("low byte read before matching high byte", analysis["warnings"][0]["message"])
|
||||
self.assertIn("check TEMP ordering", peripheral_comment_for_instruction(analysis, 0x1000))
|
||||
|
||||
def test_ad_upper_byte_read_alone_is_allowed_for_8_bit_accuracy(self):
|
||||
instructions = {
|
||||
0x1000: Instruction(
|
||||
0x1000,
|
||||
bytes.fromhex("15FEE005"),
|
||||
"MOV:G.B",
|
||||
"@ADDRA_H, R0",
|
||||
references=[0xFEE0],
|
||||
),
|
||||
}
|
||||
|
||||
analysis = analyze_peripheral_access(instructions)
|
||||
|
||||
self.assertEqual(analysis["warnings"], [])
|
||||
self.assertIn("valid 8-bit result", peripheral_comment_for_instruction(analysis, 0x1000))
|
||||
|
||||
def test_json_includes_top_level_warnings_and_instruction_metadata(self):
|
||||
instructions = {
|
||||
0x1000: Instruction(
|
||||
0x1000,
|
||||
b"",
|
||||
"MOV:G.B",
|
||||
"@ADDRA_L, R0",
|
||||
references=[0xFEE1],
|
||||
),
|
||||
}
|
||||
analysis = analyze_peripheral_access(instructions)
|
||||
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
path = Path(tmp) / "out.json"
|
||||
write_json(path, instructions, {}, {}, peripheral_access=analysis)
|
||||
payload = json.loads(path.read_text(encoding="utf-8"))
|
||||
|
||||
self.assertEqual(payload["peripheral_access"]["warnings"][0]["register"], "ADDRA")
|
||||
instruction = payload["instructions"][0]
|
||||
self.assertEqual(instruction["peripheral_access"][0]["register"], "ADDRA")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
126
tests/test_pseudocode.py
Normal file
126
tests/test_pseudocode.py
Normal file
@@ -0,0 +1,126 @@
|
||||
import unittest
|
||||
|
||||
from h8536.pseudocode import PseudocodeOptions, generate_pseudocode, split_operands
|
||||
|
||||
|
||||
class PseudocodeTest(unittest.TestCase):
|
||||
def test_split_operands_keeps_displacement_expression_together(self):
|
||||
self.assertEqual(split_operands("@(H'04,R6), R0"), ["@(H'04,R6)", "R0"])
|
||||
self.assertEqual(split_operands("{R0,R1}, @-SP"), ["{R0,R1}", "@-SP"])
|
||||
|
||||
def test_generates_c_like_function_from_decompiler_json(self):
|
||||
payload = {
|
||||
"vectors": [{"address": 0, "name": "reset", "target": 0x0100, "target_label": "vec_reset_0100"}],
|
||||
"call_graph": {
|
||||
"nodes": [
|
||||
{
|
||||
"start": 0x0100,
|
||||
"end": 0x0110,
|
||||
"label": "vec_reset_0100",
|
||||
"sources": ["reset"],
|
||||
"instruction_count": 5,
|
||||
"calls": [0x0200],
|
||||
},
|
||||
{
|
||||
"start": 0x0200,
|
||||
"end": 0x0200,
|
||||
"label": "loc_0200",
|
||||
"sources": [],
|
||||
"instruction_count": 1,
|
||||
"calls": [],
|
||||
},
|
||||
],
|
||||
"edges": [],
|
||||
},
|
||||
"instructions": [
|
||||
{
|
||||
"address": 0x0100,
|
||||
"text": "MOV:G.B #H'FF, @P1DDR",
|
||||
"mnemonic": "MOV:G.B",
|
||||
"operands": "#H'FF, @P1DDR",
|
||||
"kind": "normal",
|
||||
"targets": [],
|
||||
"references": [{"address": 0xFE80, "name": "P1DDR", "region": "register_field"}],
|
||||
"comment": "P1DDR = H'FF",
|
||||
"peripheral_access": [
|
||||
{
|
||||
"register": "FRT2_FRC",
|
||||
"direction": "write",
|
||||
"size": "W",
|
||||
"byte": "high",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"address": 0x0105,
|
||||
"text": "MOV:G.B #H'80, @RAMCR",
|
||||
"mnemonic": "MOV:G.B",
|
||||
"operands": "#H'80, @RAMCR",
|
||||
"kind": "normal",
|
||||
"targets": [],
|
||||
"references": [{"address": 0xFF11, "name": "RAMCR", "region": "register_field"}],
|
||||
"comment": "RAMCR = H'80",
|
||||
"sci": {
|
||||
"inferences": [
|
||||
{"comment": "SCI1 async baud 31250 bps"},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
"address": 0x010A,
|
||||
"text": "BNE loc_0110",
|
||||
"mnemonic": "BNE",
|
||||
"operands": "loc_0110",
|
||||
"kind": "branch",
|
||||
"targets": [0x0110],
|
||||
"references": [],
|
||||
"comment": "",
|
||||
},
|
||||
{
|
||||
"address": 0x010C,
|
||||
"text": "BSR loc_0200",
|
||||
"mnemonic": "BSR",
|
||||
"operands": "loc_0200",
|
||||
"kind": "call",
|
||||
"targets": [0x0200],
|
||||
"references": [],
|
||||
"comment": "",
|
||||
},
|
||||
{
|
||||
"address": 0x0110,
|
||||
"text": "RTS",
|
||||
"mnemonic": "RTS",
|
||||
"operands": "",
|
||||
"kind": "return",
|
||||
"targets": [],
|
||||
"references": [],
|
||||
"comment": "",
|
||||
},
|
||||
{
|
||||
"address": 0x0200,
|
||||
"text": "RTS",
|
||||
"mnemonic": "RTS",
|
||||
"operands": "",
|
||||
"kind": "return",
|
||||
"targets": [],
|
||||
"references": [],
|
||||
"comment": "",
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
text = generate_pseudocode(payload, options=PseudocodeOptions())
|
||||
|
||||
self.assertIn("void vec_reset_0100(void)", text)
|
||||
self.assertIn("P1DDR = (uint8_t)(0xFF);", text)
|
||||
self.assertIn("RAMCR = (uint8_t)(0x80);", text)
|
||||
self.assertIn("SCI1 async baud 31250 bps", text)
|
||||
self.assertIn("FRT2_FRC W write high TEMP access", text)
|
||||
self.assertIn("if (!Z) goto loc_0110;", text)
|
||||
self.assertIn("loc_0200();", text)
|
||||
self.assertIn("loc_0110:", text)
|
||||
self.assertIn("return;", text)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
122
tests/test_sci_inference.py
Normal file
122
tests/test_sci_inference.py
Normal file
@@ -0,0 +1,122 @@
|
||||
import json
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
from h8536.model import Instruction
|
||||
from h8536.render import format_listing, write_json
|
||||
from h8536.rom import Rom
|
||||
from h8536.sci import analyze_sci, sci_comment_for_instruction
|
||||
|
||||
|
||||
def sci1_setup(scr: int = 0x3C) -> dict[int, Instruction]:
|
||||
return {
|
||||
0x1000: Instruction(
|
||||
0x1000,
|
||||
bytes.fromhex("15FED80624"),
|
||||
"MOV:G.B",
|
||||
"#H'24, @SCI1_SMR",
|
||||
references=[0xFED8],
|
||||
comment="SCI1_SMR = H'24",
|
||||
),
|
||||
0x1005: Instruction(
|
||||
0x1005,
|
||||
bytes([0x15, 0xFE, 0xDA, 0x06, scr]),
|
||||
"MOV:G.B",
|
||||
f"#H'{scr:02X}, @SCI1_SCR",
|
||||
references=[0xFEDA],
|
||||
comment=f"SCI1_SCR = H'{scr:02X}",
|
||||
),
|
||||
0x100A: Instruction(
|
||||
0x100A,
|
||||
bytes.fromhex("15FED90607"),
|
||||
"MOV:G.B",
|
||||
"#H'07, @SCI1_BRR",
|
||||
references=[0xFED9],
|
||||
comment="SCI1_BRR = H'07",
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
class SciInferenceTest(unittest.TestCase):
|
||||
def test_async_internal_baud_uses_manual_brr_formula(self):
|
||||
analysis = analyze_sci(sci1_setup(), clock_hz=16_000_000)
|
||||
config = analysis["channels"]["SCI1"]["configurations"][0]
|
||||
|
||||
self.assertEqual(config["mode"], "async")
|
||||
self.assertEqual(config["cks_n"], 0)
|
||||
self.assertEqual(config["brr"], 7)
|
||||
self.assertEqual(config["baud_bps"], 31_250)
|
||||
self.assertEqual(config["formula"], "B = clock_hz / (64 * 2^(2n) * (N + 1))")
|
||||
self.assertIn("SCI1 async 8-bit even parity 1 stop baud 31250 bps", config["comment"])
|
||||
|
||||
def test_missing_clock_keeps_baud_partial(self):
|
||||
analysis = analyze_sci(sci1_setup(), clock_hz=None)
|
||||
comment = sci_comment_for_instruction(analysis, 0x100A)
|
||||
config = analysis["channels"]["SCI1"]["configurations"][0]
|
||||
|
||||
self.assertIsNone(config["baud_bps"])
|
||||
self.assertEqual(config["reason"], "clock_hz_missing")
|
||||
self.assertIn("baud needs --clock-hz", comment)
|
||||
self.assertNotIn("31250 bps", comment)
|
||||
|
||||
def test_external_clock_selection_suppresses_internal_baud(self):
|
||||
analysis = analyze_sci(sci1_setup(scr=0x3E), clock_hz=16_000_000)
|
||||
config = analysis["channels"]["SCI1"]["configurations"][0]
|
||||
|
||||
self.assertIsNone(config["baud_bps"])
|
||||
self.assertEqual(config["clock_source"], "external")
|
||||
self.assertEqual(config["reason"], "external_clock_selected")
|
||||
self.assertIn("external clock selected", config["comment"])
|
||||
|
||||
def test_scr_bit_writes_are_tracked_without_repeating_same_baud(self):
|
||||
instructions = sci1_setup()
|
||||
instructions[0x1010] = Instruction(
|
||||
0x1010,
|
||||
bytes.fromhex("15FEDAC7"),
|
||||
"BSET.B",
|
||||
"#7, @SCI1_SCR",
|
||||
references=[0xFEDA],
|
||||
comment="set TIE (bit 7) of SCI1_SCR",
|
||||
)
|
||||
|
||||
analysis = analyze_sci(instructions, clock_hz=16_000_000)
|
||||
writes = analysis["channels"]["SCI1"]["writes"]
|
||||
|
||||
self.assertEqual([write["register"] for write in writes], ["SMR", "SCR", "BRR", "SCR"])
|
||||
self.assertEqual(writes[-1]["value"], 0xBC)
|
||||
self.assertNotIn(0x1010, analysis["annotations"])
|
||||
|
||||
def test_listing_preserves_existing_comment_and_appends_sci_comment(self):
|
||||
instructions = sci1_setup()
|
||||
analysis = analyze_sci(instructions, clock_hz=16_000_000)
|
||||
|
||||
listing = format_listing(
|
||||
Path("rom.bin"),
|
||||
Rom(b"\xFF" * 0x20),
|
||||
instructions,
|
||||
{},
|
||||
{},
|
||||
"min",
|
||||
traced=False,
|
||||
sci_analysis=analysis,
|
||||
)
|
||||
|
||||
self.assertIn("SCI1_BRR = H'07; SCI1 async 8-bit even parity 1 stop baud 31250 bps", listing)
|
||||
|
||||
def test_json_includes_top_level_and_instruction_sci_metadata(self):
|
||||
instructions = sci1_setup()
|
||||
analysis = analyze_sci(instructions, clock_hz=16_000_000)
|
||||
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
path = Path(tmp) / "out.json"
|
||||
write_json(path, instructions, {}, {}, sci_analysis=analysis)
|
||||
payload = json.loads(path.read_text(encoding="utf-8"))
|
||||
|
||||
self.assertEqual(payload["sci"]["channels"]["SCI1"]["configurations"][0]["baud_bps"], 31_250)
|
||||
brr_instruction = next(item for item in payload["instructions"] if item["address"] == 0x100A)
|
||||
self.assertEqual(brr_instruction["sci"]["inferences"][0]["brr"], 7)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
47
tests/test_timing_summary.py
Normal file
47
tests/test_timing_summary.py
Normal file
@@ -0,0 +1,47 @@
|
||||
import unittest
|
||||
|
||||
from h8536.cycles import annotate_cycles
|
||||
from h8536.model import Instruction
|
||||
from h8536.timing import cycle_bounds, summarize_timing
|
||||
|
||||
|
||||
class TimingSummaryTest(unittest.TestCase):
|
||||
def test_cycle_bounds_use_branch_min_and_max(self):
|
||||
self.assertEqual(cycle_bounds({"not_taken": 3, "taken": 8}), (3, 8))
|
||||
self.assertEqual(cycle_bounds({"false": 3, "count_minus_1": 4, "taken": 8}), (3, 8))
|
||||
|
||||
def test_summarizes_backward_scb_loop_candidate(self):
|
||||
instructions = {
|
||||
0x0100: Instruction(0x0100, b"\x58\x02\x00", "MOV:I.W", "#H'0200, R0"),
|
||||
0x0103: Instruction(0x0103, b"\x01\xB8\xFD", "SCB/F", "R0, loc_0103", kind="branch", targets=[0x0103]),
|
||||
0x0106: Instruction(0x0106, b"\x19", "RTS", kind="return", fallthrough=False),
|
||||
}
|
||||
annotate_cycles(instructions, "min")
|
||||
|
||||
summary = summarize_timing(instructions, {0x0103: "loc_0103"})
|
||||
|
||||
self.assertEqual(summary["loops"][0]["start"], 0x0103)
|
||||
self.assertEqual(summary["loops"][0]["kind"], "counter_delay_loop")
|
||||
self.assertEqual(summary["loops"][0]["cycles_min"], 3)
|
||||
self.assertEqual(summary["loops"][0]["cycles_max"], 9)
|
||||
|
||||
def test_summarizes_straight_line_block_to_branch(self):
|
||||
instructions = {
|
||||
0x0200: Instruction(0x0200, b"\x58\x00\x01", "MOV:I.W", "#H'0001, R0"),
|
||||
0x0203: Instruction(0x0203, b"\x26\x02", "BNE", "loc_0207", kind="branch", targets=[0x0207]),
|
||||
0x0205: Instruction(0x0205, b"\x19", "RTS", kind="return", fallthrough=False),
|
||||
0x0207: Instruction(0x0207, b"\x19", "RTS", kind="return", fallthrough=False),
|
||||
}
|
||||
annotate_cycles(instructions, "min")
|
||||
|
||||
summary = summarize_timing(instructions, {0x0207: "loc_0207"})
|
||||
|
||||
first = summary["blocks"][0]
|
||||
self.assertEqual(first["start"], 0x0200)
|
||||
self.assertEqual(first["end"], 0x0203)
|
||||
self.assertEqual(first["cycles_min"], 6)
|
||||
self.assertEqual(first["cycles_max"], 11)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user