mirror of
https://github.com/kbeckmann/game-and-watch-retro-go.git
synced 2025-12-16 13:15:55 +01:00
* automatically launch openocd * Add "monitor" and "flash-monitor" targets to launch logpoll
132 lines
3.5 KiB
Python
Executable File
132 lines
3.5 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
import argparse
|
|
import subprocess
|
|
import sys
|
|
from time import sleep
|
|
|
|
from elftools.elf.elffile import ELFFile
|
|
from openocd import OpenOCD
|
|
|
|
|
|
def get_symbol_by_symbol_name(elffile, symbol_name):
|
|
return elffile.get_section_by_name(".symtab").get_symbol_by_name(symbol_name)[0]
|
|
|
|
|
|
def strtohex(data):
|
|
return map(strtohex, data) if isinstance(data, list) else int(data, 16)
|
|
|
|
|
|
# OpenOCD class cherry-picked/inspired from from https://github.com/zmarvel/python-openocd
|
|
|
|
|
|
def logpoll(args):
|
|
with OpenOCD(host=args.host, port=args.port) as ocd:
|
|
last_idx = 0
|
|
|
|
with open(args.elf, "rb") as f:
|
|
elffile = ELFFile(f)
|
|
logbuf = get_symbol_by_symbol_name(elffile, "logbuf")
|
|
logbuf_addr = logbuf.entry.st_value
|
|
logbuf_size = logbuf.entry.st_size
|
|
log_idx_addr = get_symbol_by_symbol_name(elffile, "log_idx").entry.st_value
|
|
|
|
ocd.send("resume")
|
|
|
|
while True:
|
|
if args.halt:
|
|
ocd.send("halt")
|
|
|
|
log_idx = ocd.read_memory(32, log_idx_addr, 1)[0]
|
|
|
|
if log_idx > last_idx:
|
|
# print the new data since last iteration
|
|
logbuf = ocd.read_memory(8, logbuf_addr + last_idx, log_idx - last_idx)
|
|
logbuf_str = "".join([chr(c) for c in logbuf])
|
|
sys.stdout.write(logbuf_str)
|
|
elif log_idx > 0 and log_idx < last_idx:
|
|
# Get new data from the end of the buffer until the first null byte
|
|
logbuf = ocd.read_memory(
|
|
8, logbuf_addr + last_idx, logbuf_size - last_idx
|
|
)
|
|
if 0 in logbuf:
|
|
end = logbuf.index(0) - 1
|
|
else:
|
|
end = len(logbuf)
|
|
logbuf_str = "".join([chr(c) for c in logbuf[:end]])
|
|
|
|
# Read new data from the beginning and append it
|
|
logbuf = ocd.read_memory(8, logbuf_addr, log_idx)
|
|
logbuf_str += "".join([chr(c) for c in logbuf])
|
|
sys.stdout.write(logbuf_str)
|
|
|
|
if args.halt:
|
|
ocd.send("resume")
|
|
|
|
last_idx = log_idx
|
|
sleep(args.interval / 1000)
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(
|
|
description="Polls the stdout log from a running target"
|
|
)
|
|
parser.add_argument(
|
|
"--elf",
|
|
type=str,
|
|
default="build/gw_retro_go.elf",
|
|
help="Game and Watch Retro-Go ELF file",
|
|
)
|
|
parser.add_argument(
|
|
"--interval",
|
|
"-i",
|
|
type=int,
|
|
default=100,
|
|
help="Polling interval (ms)",
|
|
)
|
|
parser.add_argument(
|
|
"--host",
|
|
type=str,
|
|
default="127.0.0.1",
|
|
help="OpenOCD TCL hostname",
|
|
)
|
|
parser.add_argument(
|
|
"--port",
|
|
type=int,
|
|
default=6666,
|
|
help="OpenOCD TCL port",
|
|
)
|
|
parser.add_argument(
|
|
"--halt",
|
|
dest="halt",
|
|
action="store_true",
|
|
help="Halts the target during memory reads",
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
try:
|
|
logpoll(args)
|
|
return
|
|
except ConnectionRefusedError:
|
|
pass
|
|
|
|
# Attempt to automagically launch openocd
|
|
try:
|
|
p = subprocess.Popen(
|
|
["make", "openocd"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
|
|
)
|
|
sleep(1) # Give openocd some time to launch
|
|
logpoll(args)
|
|
except KeyboardInterrupt:
|
|
pass
|
|
|
|
try:
|
|
p.terminate()
|
|
except OSError:
|
|
pass
|
|
p.wait()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|