litescope_gui: Add initial and very simple GUI support.

This commit is contained in:
Florent Kermarrec 2022-03-16 16:56:07 +01:00
parent 1d85cbcb6d
commit f1acdf4c17
1 changed files with 102 additions and 36 deletions

View File

@ -11,6 +11,8 @@ import os
import re import re
import csv import csv
import sys import sys
import time
import threading
import argparse import argparse
from litex import RemoteClient from litex import RemoteClient
@ -23,7 +25,7 @@ def get_signals(csvname, group):
with open(csvname) as f: with open(csvname) as f:
reader = csv.reader(f, delimiter=",", quotechar="#") reader = csv.reader(f, delimiter=",", quotechar="#")
for t, g, n, v in reader: for t, g, n, v in reader:
if t == "signal" and g == group: if t == "signal" and g == str(group):
signals.append(n) signals.append(n)
return signals return signals
@ -74,41 +76,119 @@ def add_triggers(args, analyzer, signals):
added = True added = True
return added return added
# Run Batch/GUI -----------------------------------------------------------------------------------
def run_batch(args):
bus = RemoteClient(csr_csv=args.csr_csv)
bus.open()
basename = os.path.splitext(os.path.basename(args.csv))[0]
signals = get_signals(args.csv, args.group)
# Configure and run LiteScope analyzer.
analyzer = LiteScopeAnalyzerDriver(bus.regs, basename, debug=True)
analyzer.configure_group(args.group)
analyzer.configure_subsampler(args.subsampling)
if not add_triggers(args, analyzer, signals):
print("No trigger, immediate capture.")
analyzer.run(
offset = int(args.offset, 0),
length = None if args.length is None else int(args.length, 0)
)
analyzer.wait_done()
analyzer.upload()
analyzer.save(args.dump)
# Close remove control.
bus.close()
def run_gui(args):
import dearpygui.dearpygui as dpg
bus = RemoteClient(csr_csv=args.csr_csv)
bus.open()
triggers = get_signals(args.csv, args.group)
def capture_callback():
basename = os.path.splitext(os.path.basename(args.csv))[0]
analyzer = LiteScopeAnalyzerDriver(bus.regs, basename, debug=True)
analyzer.configure_group(int(dpg.get_value(item="capture_group"), 0))
analyzer.configure_subsampler(int(dpg.get_value(item="capture_subsampling"), 0))
trigger_cond = {}
for trigger in triggers:
trigger_cond[trigger] = dpg.get_value(trigger)
analyzer.add_trigger(cond=trigger_cond)
analyzer.run(
offset = int(dpg.get_value(item="capture_offset"), 0),
length = int(dpg.get_value(item="capture_length"), 0),
)
dpg.set_value("capture_status", "Running...")
analyzer.wait_done()
dpg.set_value("capture_status", "Uploading...")
analyzer.upload()
dpg.set_value("capture_status", "Writing...")
analyzer.save(dpg.get_value(item="capture_dump"))
dpg.set_value("capture_status", "Idle")
dpg.create_context()
dpg.create_viewport(title="LiteScope CLI GUI", max_width=400, always_on_top=True)
dpg.setup_dearpygui()
with dpg.window(label="Capture", autosize=True):
dpg.add_text("Parameters")
dpg.add_input_text(indent=8, label="Offset", tag="capture_offset", default_value=args.offset)
dpg.add_input_text(indent=8, label="Length", tag="capture_length", default_value="128") # FIXME
dpg.add_input_text(indent=8, label="Group", tag="capture_group", default_value="0") # FIXME
dpg.add_input_text(indent=8, label="Subsampling", tag="capture_subsampling", default_value="1") # FIXME
dpg.add_input_text(indent=8, label="Dump", tag="capture_dump", default_value=args.dump)
dpg.add_text("Control/Status")
with dpg.group(horizontal=True):
dpg.add_button(label="Run", callback=capture_callback)
dpg.add_text(tag="capture_status", default_value="Idle")
with dpg.window(label="Triggers", autosize=True, pos=(0, 250)):
for trigger in triggers:
dpg.add_input_text(indent=8, label=trigger, tag=trigger, default_value="0bx", width=100)
dpg.show_viewport()
dpg.start_dearpygui()
dpg.destroy_context()
bus.close()
# Main --------------------------------------------------------------------------------------------- # Main ---------------------------------------------------------------------------------------------
def parse_args(): def parse_args():
parser = argparse.ArgumentParser(description="""LiteScope Client utility""") parser = argparse.ArgumentParser(description="""LiteScope Client utility""")
parser.add_argument("-r", "--rising-edge", action="append", help="Add rising edge trigger") parser.add_argument("-r", "--rising-edge", action="append", help="Add rising edge trigger.")
parser.add_argument("-f", "--falling-edge", action="append", help="Add falling edge trigger") parser.add_argument("-f", "--falling-edge", action="append", help="Add falling edge trigger.")
parser.add_argument("-v", "--value-trigger", action="append", nargs=2, help="Add conditional trigger with given value", parser.add_argument("-v", "--value-trigger", action="append", nargs=2, help="Add conditional trigger with given value.",
metavar=("TRIGGER", "VALUE")) metavar=("TRIGGER", "VALUE"))
parser.add_argument("-l", "--list", action="store_true", help="List signal choices") parser.add_argument("-l", "--list", action="store_true", help="List signal choices.")
parser.add_argument("--csv", default="analyzer.csv", help="Analyzer CSV file") parser.add_argument("--csv", default="analyzer.csv", help="Analyzer CSV file.")
parser.add_argument("--csr-csv", default="csr.csv", help="SoC CSV file") parser.add_argument("--csr-csv", default="csr.csv", help="SoC CSV file.")
parser.add_argument("--group", default="0", help="Capture Group") parser.add_argument("--group", default=0, type=int, help="Capture Group.")
parser.add_argument("--subsampling", default="1", help="Capture Subsampling") parser.add_argument("--subsampling", default=1, type=int, help="Capture Subsampling.")
parser.add_argument("--offset", default="32", help="Capture Offset") parser.add_argument("--offset", default="32", help="Capture Offset.")
parser.add_argument("--length", default=None, help="Capture Length") parser.add_argument("--length", default=None, help="Capture Length.")
parser.add_argument("--dump", default="dump.vcd", help="Capture Filename") parser.add_argument("--dump", default="dump.vcd", help="Capture Filename.")
parser.add_argument("--gui", action="store_true", help="Run Gui.")
args = parser.parse_args() args = parser.parse_args()
return args return args
def main(): def main():
args = parse_args() args = parse_args()
basename = os.path.splitext(os.path.basename(args.csv))[0]
# Check if analyzer file is present and exit if not. # Check if analyzer file is present and exit if not.
if not os.path.exists(args.csv): if not os.path.exists(args.csv):
raise ValueError("{} not found. This is necessary to load the wires which have been tapped to scope." raise ValueError("{} not found. This is necessary to load the wires which have been tapped to scope."
"Try setting --csv to value of the csr_csv argument to LiteScopeAnalyzer in the SoC.".format(args.csv)) "Try setting --csv to value of the csr_csv argument to LiteScopeAnalyzer in the SoC.".format(args.csv))
sys.exit(1) sys.exit(1)
# Get list of signals from analyzer configuratio file.
signals = get_signals(args.csv, args.group)
# If in list mode, list signals and exit. # If in list mode, list signals and exit.
if args.list: if args.list:
signals = get_signals(args.csv, args.group)
for signal in signals: for signal in signals:
print(signal) print(signal)
sys.exit(0) sys.exit(0)
@ -117,27 +197,13 @@ def main():
if not os.path.exists(args.csr_csv): if not os.path.exists(args.csr_csv):
raise ValueError("{} not found. This is necessary to load the 'regs' of the remote. Try setting --csr-csv here to " raise ValueError("{} not found. This is necessary to load the 'regs' of the remote. Try setting --csr-csv here to "
"the path to the --csr-csv argument of the SoC build.".format(args.csr_csv)) "the path to the --csr-csv argument of the SoC build.".format(args.csr_csv))
bus = RemoteClient(csr_csv=args.csr_csv)
bus.open()
# Configure and run LiteScope analyzer. # Run Batch/Gui.
try: if args.gui:
analyzer = LiteScopeAnalyzerDriver(bus.regs, basename, debug=True) run_gui(args)
analyzer.configure_group(int(args.group, 0)) else:
analyzer.configure_subsampler(int(args.subsampling, 0)) run_batch(args)
if not add_triggers(args, analyzer, signals):
print("No trigger, immediate capture.")
analyzer.run(
offset = int(args.offset, 0),
length = None if args.length is None else int(args.length, 0)
)
analyzer.wait_done()
analyzer.upload()
analyzer.save(args.dump)
# Close remove control.
finally:
bus.close()
if __name__ == "__main__": if __name__ == "__main__":
main() main()