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 csv
import sys
import time
import threading
import argparse
from litex import RemoteClient
@ -23,7 +25,7 @@ def get_signals(csvname, group):
with open(csvname) as f:
reader = csv.reader(f, delimiter=",", quotechar="#")
for t, g, n, v in reader:
if t == "signal" and g == group:
if t == "signal" and g == str(group):
signals.append(n)
return signals
@ -74,57 +76,19 @@ def add_triggers(args, analyzer, signals):
added = True
return added
# Main ---------------------------------------------------------------------------------------------
# Run Batch/GUI -----------------------------------------------------------------------------------
def parse_args():
parser = argparse.ArgumentParser(description="""LiteScope Client utility""")
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("-v", "--value-trigger", action="append", nargs=2, help="Add conditional trigger with given value",
metavar=("TRIGGER", "VALUE"))
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("--csr-csv", default="csr.csv", help="SoC CSV file")
parser.add_argument("--group", default="0", help="Capture Group")
parser.add_argument("--subsampling", default="1", help="Capture Subsampling")
parser.add_argument("--offset", default="32", help="Capture Offset")
parser.add_argument("--length", default=None, help="Capture Length")
parser.add_argument("--dump", default="dump.vcd", help="Capture Filename")
args = parser.parse_args()
return args
def main():
args = parse_args()
basename = os.path.splitext(os.path.basename(args.csv))[0]
# Check if analyzer file is present and exit if not.
if not os.path.exists(args.csv):
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))
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 args.list:
for signal in signals:
print(signal)
sys.exit(0)
# Create and open remote control.
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 "
"the path to the --csr-csv argument of the SoC build.".format(args.csr_csv))
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.
try:
analyzer = LiteScopeAnalyzerDriver(bus.regs, basename, debug=True)
analyzer.configure_group(int(args.group, 0))
analyzer.configure_subsampler(int(args.subsampling, 0))
analyzer.configure_group(args.group)
analyzer.configure_subsampler(args.subsampling)
if not add_triggers(args, analyzer, signals):
print("No trigger, immediate capture.")
analyzer.run(
@ -136,8 +100,110 @@ def main():
analyzer.save(args.dump)
# Close remove control.
finally:
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 ---------------------------------------------------------------------------------------------
def parse_args():
parser = argparse.ArgumentParser(description="""LiteScope Client utility""")
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("-v", "--value-trigger", action="append", nargs=2, help="Add conditional trigger with given value.",
metavar=("TRIGGER", "VALUE"))
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("--csr-csv", default="csr.csv", help="SoC CSV file.")
parser.add_argument("--group", default=0, type=int, help="Capture Group.")
parser.add_argument("--subsampling", default=1, type=int, help="Capture Subsampling.")
parser.add_argument("--offset", default="32", help="Capture Offset.")
parser.add_argument("--length", default=None, help="Capture Length.")
parser.add_argument("--dump", default="dump.vcd", help="Capture Filename.")
parser.add_argument("--gui", action="store_true", help="Run Gui.")
args = parser.parse_args()
return args
def main():
args = parse_args()
# Check if analyzer file is present and exit if not.
if not os.path.exists(args.csv):
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))
sys.exit(1)
# If in list mode, list signals and exit.
if args.list:
signals = get_signals(args.csv, args.group)
for signal in signals:
print(signal)
sys.exit(0)
# Create and open remote control.
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 "
"the path to the --csr-csv argument of the SoC build.".format(args.csr_csv))
# Run Batch/Gui.
if args.gui:
run_gui(args)
else:
run_batch(args)
if __name__ == "__main__":
main()