diff options
Diffstat (limited to 'atk16_emu')
| -rw-r--r-- | atk16_emu/cli.py | 21 | ||||
| -rw-r--r-- | atk16_emu/debugger.py | 98 | ||||
| -rw-r--r-- | atk16_emu/emu.py | 8 |
3 files changed, 119 insertions, 8 deletions
diff --git a/atk16_emu/cli.py b/atk16_emu/cli.py index 7aa4b6b..d6bd46b 100644 --- a/atk16_emu/cli.py +++ b/atk16_emu/cli.py @@ -1,6 +1,7 @@ import sys from dataclasses import dataclass from .emu import Machine +from .debugger import Debugger @dataclass class Options: @@ -43,12 +44,18 @@ def load_rom_image_from_path(path: str) -> bytearray: rom_image = load_rom_image_from_path(options.rom_image_path) -machine = Machine() -machine.load_rom_image(rom_image) -machine.reset() -machine.run_until_halted() +if not options.debugger_enabled: + machine = Machine() + machine.load_rom_image(rom_image) + machine.reset() + machine.run_until_halted() -print("Machine halted.") -print("===============") + print("Machine halted.") + print("===============") -machine.print_state_summary() + machine.print_state_summary() + +else: + debugger = Debugger() + debugger.load_rom_image(rom_image) + debugger.activate() diff --git a/atk16_emu/debugger.py b/atk16_emu/debugger.py new file mode 100644 index 0000000..f887ed0 --- /dev/null +++ b/atk16_emu/debugger.py @@ -0,0 +1,98 @@ +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": + self.machine.step() + elif cmd == "s": + self.machine.print_state_summary() + elif cmd == "0": + self.machine.reset() + 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() diff --git a/atk16_emu/emu.py b/atk16_emu/emu.py index 591eeb5..8eeb6b1 100644 --- a/atk16_emu/emu.py +++ b/atk16_emu/emu.py @@ -208,6 +208,8 @@ class Machine: instr = self.mem_read(pc_addr) instruction = self.decode(instr) + #print(f"Executing instruction 0b{instr:>016b} (0x{instr:>04x}) at address 0x{pc_addr:>04x}") + try: match instruction: case ALR(target, left, right, alu_code): @@ -254,6 +256,8 @@ class Machine: self.pc.value = addr case JPI(imm): + # convert imm from signed (twos complement) 9-bit to a python int + imm = (imm & (0b011111111)) - (imm & 0b100000000) self.pc.value = (self.pc.value + imm) & 0xFFFF case BRR(flag, addr_reg): @@ -262,6 +266,8 @@ class Machine: self.pc.value = addr case BRI(flag, addr_imm): + # convert imm from signed (twos complement) 9-bit to a python int + addr_imm = (addr_imm & (0b011111111)) - (addr_imm & 0b100000000) if self.check_nth_flag(flag): self.pc.value = (self.pc.value + addr_imm) & 0xFFFF @@ -288,7 +294,7 @@ class Machine: self.running = False except: - print(f"Error while executing instruction {instr:>016b} ({instr:>04x}) at address {pc_addr:>04x}", file=sys.stderr) + print(f"Error while executing instruction 0b{instr:>016b} (0x{instr:>04x}) at address 0x{pc_addr:>04x}", file=sys.stderr) raise def decode(self, instr: int): |
