aboutsummaryrefslogtreecommitdiffstats
path: root/atk16_emu/debugger.py
blob: 3d8f1318302ded7a02f682320e23ff77b36421c7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
from getch import getche
from .emu import Machine

class Debugger:
  def __init__(self):
    self.rom_image = None
    self.breakpoints: set[int] = set()
    self.machine = Machine()
    self.machine.reset()
    self.machine.run()

  def load_rom_image(self, rom_image: bytearray) -> None:
    self.rom_image = rom_image
    self.machine.load_rom_image(rom_image)

    print("Loaded rom image.")

  def print_pc_context(self):
    print("=== Program context")
    for i in range(-4, 5):
      addr = self.machine.pc.value + i
      if addr < 0 or addr >= 64 * 2 ** 16:
        continue

      if i == 0:
        print(f"> 0x{addr:>04x}: 0x{self.machine.mem_read(addr):>04x}")
      else:
        print(f"  0x{addr:>04x}: 0x{self.machine.mem_read(addr):>04x}")

    print()

  def activate(self):
    print("=== ATK16 debugger ===")
    print("Press ? to show command help. Press q to quit.")
    print()

    while True:
      self.print_pc_context()
      print("dbg> ", end="", flush=True)
      cmd = getche()
      print()

      if cmd == "q":
        break
      elif cmd == "?":
        self.print_help()
      elif cmd == "r":
        while self.machine.running:
          self.machine.step()
          if self.machine.pc.value in self.breakpoints:
            print(f"Breakpoint hit at 0x{self.machine.pc.value:>04x}")
            break

        if not self.machine.running:
          print("Machine halted.")

      elif cmd == "b":
        print("Set breakpoints:")
        for addr in self.breakpoints:
          print(f"  0x{addr:>04x}")
        if len(self.breakpoints) == 0:
          print("<no breakpoints>")
        print()

        try:
          addr = eval(input("Breakpoint address: "), {})
        except:
          print("Cancelled")
          continue
        if type(addr) != int or addr < 0 or addr >= 64 * 2 ** 16:
          print("Invalid address")

        if addr in self.breakpoints:
          self.breakpoints.remove(addr)
          print(f"Removed breakpoint at 0x{addr:>04x}")
        else:
          self.breakpoints.add(addr)
      elif cmd == "n":
        if not self.machine.running:
          print("Machine halted.")
          continue

        self.machine.step()

        if not self.machine.running:
          print("Machine halted.")
      elif cmd == "s":
        self.machine.print_state_summary()
      elif cmd == "0":
        self.machine.reset()
        self.machine.run()
        print("Machine reset.")
      else:
        print(f"Unknown command: {cmd}")

  def print_help(self):
    print("Debugger commands:")
    print("  r     run until next breakpoint or until halted")
    print("  n     step forward")
    print("  b     step backward")
    print("  b     set or remove breakpoint")
    print("  s     show state summary")
    print("  0     reset the machine state")
    print("  q     quit")
    print("  ?     show this help")
    print()