comm_analyzer, waveform add ndecimals

This commit is contained in:
Simon Renblad 2024-02-07 16:44:53 +08:00 committed by Sébastien Bourdeauducq
parent efb8aaf9f9
commit 720cbb4490
2 changed files with 56 additions and 35 deletions

View File

@ -8,11 +8,15 @@ from enum import Enum
import struct import struct
import logging import logging
import socket import socket
import math
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
DEFAULT_REF_PERIOD = 1e-9
class MessageType(Enum): class MessageType(Enum):
output = 0b00 output = 0b00
input = 0b01 input = 0b01
@ -228,7 +232,7 @@ class VCDManager:
def set_timescale_ps(self, timescale): def set_timescale_ps(self, timescale):
self.out.write("$timescale {}ps $end\n".format(round(timescale))) self.out.write("$timescale {}ps $end\n".format(round(timescale)))
def get_channel(self, name, width, ty): def get_channel(self, name, width, ty, ndecimals=0):
code = next(self.codes) code = next(self.codes)
self.out.write("$var wire {width} {code} {name} $end\n" self.out.write("$var wire {width} {code} {name} $end\n"
.format(name=name, code=code, width=width)) .format(name=name, code=code, width=width))
@ -265,9 +269,9 @@ class WaveformManager:
def set_timescale_ps(self, timescale): def set_timescale_ps(self, timescale):
self.trace["timescale"] = int(timescale) self.trace["timescale"] = int(timescale)
def get_channel(self, name, width, ty): def get_channel(self, name, width, ty, ndecimals=0):
if ty == WaveformType.LOG: if ty == WaveformType.LOG:
self.trace["logs"][self.current_scope + name] = (width, ty) self.trace["logs"][self.current_scope + name] = (width, ty, ndecimals)
data = self.trace["data"][self.current_scope + name] = list() data = self.trace["data"][self.current_scope + name] = list()
channel = WaveformChannel(data, self.current_time) channel = WaveformChannel(data, self.current_time)
self.channels.append(channel) self.channels.append(channel)
@ -318,8 +322,8 @@ class ChannelSignatureManager:
self.current_scope = "" self.current_scope = ""
self.channels = dict() self.channels = dict()
def get_channel(self, name, width, ty): def get_channel(self, name, width, ty, ndecimals=0):
self.channels[self.current_scope + name] = (width, ty) self.channels[self.current_scope + name] = (width, ty, ndecimals)
return None return None
@contextmanager @contextmanager
@ -361,8 +365,9 @@ class TTLClockGenHandler:
def __init__(self, manager, name, ref_period): def __init__(self, manager, name, ref_period):
self.name = name self.name = name
self.ref_period = ref_period self.ref_period = ref_period
ndecimals = max(0, math.ceil(math.log10(2**24 * ref_period)))
self.channel_frequency = manager.get_channel( self.channel_frequency = manager.get_channel(
"ttl_clkgen/" + name, 64, ty=WaveformType.ANALOG) "ttl_clkgen/" + name, 64, ty=WaveformType.ANALOG, ndecimals=ndecimals)
def process_message(self, message): def process_message(self, message):
if isinstance(message, OutputMessage): if isinstance(message, OutputMessage):
@ -383,11 +388,17 @@ class DDSHandler:
def add_dds_channel(self, name, dds_channel_nr): def add_dds_channel(self, name, dds_channel_nr):
dds_channel = dict() dds_channel = dict()
frequency_decimals = max(0, math.ceil(math.log10(2**32 / self.sysclk)))
phase_decimals = max(0, math.ceil(math.log10(2**16)))
with self.manager.scope("dds", name): with self.manager.scope("dds", name):
dds_channel["vcd_frequency"] = \ dds_channel["vcd_frequency"] = \
self.manager.get_channel(name + "/frequency", 64, ty=WaveformType.ANALOG) self.manager.get_channel(name + "/frequency", 64,
ty=WaveformType.ANALOG,
ndecimals=frequency_decimals)
dds_channel["vcd_phase"] = \ dds_channel["vcd_phase"] = \
self.manager.get_channel(name + "/phase", 64, ty=WaveformType.ANALOG) self.manager.get_channel(name + "/phase", 64,
ty=WaveformType.ANALOG,
ndecimals=phase_decimals)
dds_channel["ftw"] = [None, None] dds_channel["ftw"] = [None, None]
dds_channel["pow"] = None dds_channel["pow"] = None
self.dds_channels[dds_channel_nr] = dds_channel self.dds_channels[dds_channel_nr] = dds_channel
@ -662,8 +673,12 @@ def get_channel_list(devices):
manager = ChannelSignatureManager() manager = ChannelSignatureManager()
create_channel_handlers(manager, devices, 1e-9, 3e9, False) create_channel_handlers(manager, devices, 1e-9, 3e9, False)
manager.get_channel("timestamp", 64, ty=WaveformType.VECTOR) manager.get_channel("timestamp", 64, ty=WaveformType.VECTOR)
manager.get_channel("interval", 64, ty=WaveformType.ANALOG) ref_period = get_ref_period(devices)
manager.get_channel("rtio_slack", 64, ty=WaveformType.ANALOG) if ref_period is None:
ref_period = DEFAULT_REF_PERIOD
ndecimals = max(0, math.ceil(math.log10(1 / ref_period)))
manager.get_channel("interval", 64, ty=WaveformType.ANALOG, ndecimals=ndecimals)
manager.get_channel("rtio_slack", 64, ty=WaveformType.ANALOG, ndecimals=ndecimals)
return manager.channels return manager.channels
@ -685,12 +700,11 @@ def decoded_dump_to_waveform_data(devices, dump, uniform_interval=False):
def decoded_dump_to_target(manager, devices, dump, uniform_interval): def decoded_dump_to_target(manager, devices, dump, uniform_interval):
ref_period = get_ref_period(devices) ref_period = get_ref_period(devices)
if ref_period is not None: if ref_period is None:
logger.warning("unable to determine core device ref_period")
ref_period = DEFAULT_REF_PERIOD
if not uniform_interval: if not uniform_interval:
manager.set_timescale_ps(ref_period*1e12) manager.set_timescale_ps(ref_period*1e12)
else:
logger.warning("unable to determine core device ref_period")
ref_period = 1e-9 # guess
dds_sysclk = get_dds_sysclk(devices) dds_sysclk = get_dds_sysclk(devices)
if dds_sysclk is None: if dds_sysclk is None:
logger.warning("unable to determine DDS sysclk") logger.warning("unable to determine DDS sysclk")

View File

@ -122,7 +122,8 @@ class _BackgroundItem(pg.GraphicsWidgetAnchor, pg.GraphicsWidget):
class _BaseWaveform(pg.PlotWidget): class _BaseWaveform(pg.PlotWidget):
cursorMove = QtCore.pyqtSignal(float) cursorMove = QtCore.pyqtSignal(float)
def __init__(self, name, width, parent=None, pen="r", stepMode="right", connect="finite"): def __init__(self, name, width, ndecimals,
parent=None, pen="r", stepMode="right", connect="finite"):
pg.PlotWidget.__init__(self, pg.PlotWidget.__init__(self,
parent=parent, parent=parent,
x=None, x=None,
@ -138,6 +139,8 @@ class _BaseWaveform(pg.PlotWidget):
self.name = name self.name = name
self.width = width self.width = width
self.ndecimals = ndecimals
self.x_data = [] self.x_data = []
self.y_data = [] self.y_data = []
@ -223,8 +226,8 @@ class _BaseWaveform(pg.PlotWidget):
class BitWaveform(_BaseWaveform): class BitWaveform(_BaseWaveform):
def __init__(self, name, width, parent=None): def __init__(self, name, width, ndecimals, parent=None):
_BaseWaveform.__init__(self, name, width, parent) _BaseWaveform.__init__(self, name, width, ndecimals, parent)
self._arrows = [] self._arrows = []
def onDataChange(self, data): def onDataChange(self, data):
@ -266,8 +269,9 @@ class BitWaveform(_BaseWaveform):
class AnalogWaveform(_BaseWaveform): class AnalogWaveform(_BaseWaveform):
def __init__(self, name, width, parent=None): def __init__(self, name, width, ndecimals, parent=None):
_BaseWaveform.__init__(self, name, width, parent) _BaseWaveform.__init__(self, name, width, ndecimals, parent)
self._format_string = "{:." + str(ndecimals) + "f}"
def onDataChange(self, data): def onDataChange(self, data):
_BaseWaveform.onDataChange(self, data) _BaseWaveform.onDataChange(self, data)
@ -283,12 +287,15 @@ class AnalogWaveform(_BaseWaveform):
def onCursorMove(self, x): def onCursorMove(self, x):
_BaseWaveform.onCursorMove(self, x) _BaseWaveform.onCursorMove(self, x)
self.cursor_label.setText(self.cursor_y) t = None
if self.cursor_y is not None:
t = self._format_string.format(self.cursor_y)
self.cursor_label.setText(t)
class BitVectorWaveform(_BaseWaveform): class BitVectorWaveform(_BaseWaveform):
def __init__(self, name, width, parent=None): def __init__(self, name, width, ndecimals, parent=None):
_BaseWaveform.__init__(self, name, width, parent) _BaseWaveform.__init__(self, name, width, ndecimals, parent)
self._labels = [] self._labels = []
self._format_string = "{:0=" + str(math.ceil(width / 4)) + "X}" self._format_string = "{:0=" + str(math.ceil(width / 4)) + "X}"
self.view_box.sigTransformChanged.connect(self._update_labels) self.view_box.sigTransformChanged.connect(self._update_labels)
@ -345,8 +352,8 @@ class BitVectorWaveform(_BaseWaveform):
class LogWaveform(_BaseWaveform): class LogWaveform(_BaseWaveform):
def __init__(self, name, width, parent=None): def __init__(self, name, width, ndecimals, parent=None):
_BaseWaveform.__init__(self, name, width, parent) _BaseWaveform.__init__(self, name, width, ndecimals, parent)
self.plot_data_item.opts['pen'] = None self.plot_data_item.opts['pen'] = None
self.plot_data_item.opts['symbol'] = 'x' self.plot_data_item.opts['symbol'] = 'x'
self._labels = [] self._labels = []
@ -454,8 +461,9 @@ class _WaveformView(QtWidgets.QWidget):
def onDataChange(self, top, bottom, roles): def onDataChange(self, top, bottom, roles):
first = top.row() first = top.row()
last = bottom.row() last = bottom.row()
data_row = self._model.headers.index("data")
for i in range(first, last + 1): for i in range(first, last + 1):
data = self._model.data(self._model.index(i, 3)) data = self._model.data(self._model.index(i, data_row))
self._splitter.widget(i).onDataChange(data) self._splitter.widget(i).onDataChange(data)
def onInsert(self, parent, first, last): def onInsert(self, parent, first, last):
@ -481,16 +489,15 @@ class _WaveformView(QtWidgets.QWidget):
self._splitter.widget(i).onCursorMove(x) self._splitter.widget(i).onCursorMove(x)
def _create_waveform(self, row): def _create_waveform(self, row):
name = self._model.data(self._model.index(row, 0)) name, ty, width, ndecimals = (
ty = self._model.data(self._model.index(row, 1)) self._model.data(self._model.index(row, i)) for i in range(4))
width = self._model.data(self._model.index(row, 2))
waveform_cls = { waveform_cls = {
WaveformType.BIT: BitWaveform, WaveformType.BIT: BitWaveform,
WaveformType.VECTOR: BitVectorWaveform, WaveformType.VECTOR: BitVectorWaveform,
WaveformType.ANALOG: AnalogWaveform, WaveformType.ANALOG: AnalogWaveform,
WaveformType.LOG: LogWaveform WaveformType.LOG: LogWaveform
}[ty] }[ty]
w = waveform_cls(name, width, parent=self._splitter) w = waveform_cls(name, width, ndecimals, parent=self._splitter)
w.setXLink(self._ref_vb) w.setXLink(self._ref_vb)
w.setStoppedX(self._stopped_x) w.setStoppedX(self._stopped_x)
w.setTimescale(self._timescale) w.setTimescale(self._timescale)
@ -516,7 +523,7 @@ class _WaveformView(QtWidgets.QWidget):
class _WaveformModel(QtCore.QAbstractTableModel): class _WaveformModel(QtCore.QAbstractTableModel):
def __init__(self): def __init__(self):
self.backing_struct = [] self.backing_struct = []
self.headers = ["name", "type", "width", "data"] self.headers = ["name", "type", "width", "ndecimals", "data"]
QtCore.QAbstractTableModel.__init__(self) QtCore.QAbstractTableModel.__init__(self)
def rowCount(self, parent=QtCore.QModelIndex()): def rowCount(self, parent=QtCore.QModelIndex()):
@ -557,11 +564,11 @@ class _WaveformModel(QtCore.QAbstractTableModel):
self.endRemoveRows() self.endRemoveRows()
def export_list(self): def export_list(self):
return [[row[0], row[1].value, row[2]] for row in self.backing_struct] return [[row[0], row[1].value, row[2], row[3]] for row in self.backing_struct]
def import_list(self, channel_list): def import_list(self, channel_list):
self.clear() self.clear()
data = [[row[0], WaveformType(row[1]), row[2], []] for row in channel_list] data = [[row[0], WaveformType(row[1]), row[2], row[3], []] for row in channel_list]
self.extend(data) self.extend(data)
def update_data(self, waveform_data, top, bottom): def update_data(self, waveform_data, top, bottom):
@ -669,8 +676,8 @@ class _AddChannelDialog(QtWidgets.QDialog):
for select in selection: for select in selection:
key = self._model.index_to_key(select) key = self._model.index_to_key(select)
if key is not None: if key is not None:
width, ty = self._model[key].ref width, ty, ndecimals = self._model[key].ref
channels.append([key, ty, width, []]) channels.append([key, ty, width, ndecimals, []])
self.accepted.emit(channels) self.accepted.emit(channels)
self.close() self.close()