From 46f59b673f221120cfc27fee9f89733a2e3a0727 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 20 Dec 2015 14:34:16 +0800 Subject: [PATCH] coredevice: analyzer message decoding --- artiq/coredevice/analyzer.py | 77 ++++++++++++++++++++++++++++++++ artiq/frontend/artiq_coretool.py | 25 ++--------- artiq/gateware/rtio/analyzer.py | 38 ++++------------ 3 files changed, 88 insertions(+), 52 deletions(-) create mode 100644 artiq/coredevice/analyzer.py diff --git a/artiq/coredevice/analyzer.py b/artiq/coredevice/analyzer.py new file mode 100644 index 000000000..1595ff67f --- /dev/null +++ b/artiq/coredevice/analyzer.py @@ -0,0 +1,77 @@ +from enum import Enum +from collections import namedtuple +import struct +import logging + + +logger = logging.getLogger(__name__) + + +class MessageType(Enum): + output = 0b00 + input = 0b01 + exception = 0b10 + + +class ExceptionType(Enum): + reset_rising = 0b000000 + reset_falling = 0b000001 + reset_phy_rising = 0b000010 + reset_phy_falling = 0b000011 + + o_underflow_reset = 0b010000 + o_sequence_error_reset = 0b010001 + o_collision_error_reset = 0b010010 + + i_overflow_reset = 0b100000 + + +OutputMessage = namedtuple( + "OutputMessage", "channel timestamp rtio_counter address data") + +InputMessage = namedtuple( + "InputMessage", "channel timestamp rtio_counter data") + +ExceptionMessage = namedtuple( + "ExceptionMessage", "channel rtio_counter exception_type") + + +def decode_message(data): + message_type_channel = struct.unpack(">I", data[28:32])[0] + message_type = MessageType(message_type_channel & 0b11) + channel = message_type_channel >> 2 + + if message_type == MessageType.output: + parts = struct.unpack(">QIQQ", data[:28]) + data, address, rtio_counter, timestamp = parts + return OutputMessage(channel, timestamp, rtio_counter, address, data) + elif message_type == MessageType.input: + parts = struct.unpack(">QIQQ", data[:28]) + data, _, rtio_counter, timestamp = parts + return InputMessage(channel, timestamp, rtio_counter, data) + elif message_type == MessageType.exception: + exception_type, rtio_counter = struct.unpack(">BQ", data[11:20]) + return ExceptionMessage(channel, rtio_counter, + ExceptionType(exception_type)) + + +def decode_dump(data): + parts = struct.unpack(">IQI", data[:16]) + sent_bytes, total_byte_count, overflow_occured = parts + + if sent_bytes + 16 != len(data): + raise ValueError("analyzer dump has incorrect length") + if overflow_occured: + logger.warning("analyzer FIFO overflow occured, " + "some messages have been lost") + if total_byte_count > sent_bytes: + logger.info("analyzer ring buffer has wrapped %d times", + total_byte_count//sent_bytes) + + position = 16 + messages = [] + for _ in range(sent_bytes//32): + messages.append(decode_message(data[position:position+32])) + position += 32 + return messages + diff --git a/artiq/frontend/artiq_coretool.py b/artiq/frontend/artiq_coretool.py index 12bb83da5..444f2d5fd 100755 --- a/artiq/frontend/artiq_coretool.py +++ b/artiq/frontend/artiq_coretool.py @@ -5,27 +5,7 @@ import struct from artiq.master.databases import DeviceDB from artiq.master.worker_db import DeviceManager - - -def print_analyzer_dump(dump): - sent_bytes, total_byte_count, overflow_occured = struct.unpack(">IQI", dump[:16]) - dump = dump[16:] - print(sent_bytes, total_byte_count, overflow_occured) - - while dump: - message_type_channel = struct.unpack(">I", dump[28:32])[0] - message_type = message_type_channel & 0b11 - channel = message_type_channel >> 2 - - if message_type == 2: - exception_type, rtio_counter = struct.unpack(">BQ", dump[11:20]) - print("EXC exception_type={} channel={} rtio_counter={}" - .format(exception_type, channel, rtio_counter)) - else: - (data, address_padding, rtio_counter, timestamp) = struct.unpack(">QIQQ", dump[:28]) - print("IO type={} channel={} timestamp={} rtio_counter={} address_padding={} data={}" - .format(message_type, channel, timestamp, rtio_counter, address_padding, data)) - dump = dump[32:] +from artiq.coredevice.analyzer import decode_dump def get_argparser(): @@ -100,7 +80,8 @@ def main(): comm.flash_storage_erase() elif args.action == "analyzer-dump": dump = comm.get_analyzer_dump() - print_analyzer_dump(dump) + for msg in decode_dump(dump): + print(msg) finally: device_mgr.close_devices() diff --git a/artiq/gateware/rtio/analyzer.py b/artiq/gateware/rtio/analyzer.py index 9c38d09ce..cef3cbd48 100644 --- a/artiq/gateware/rtio/analyzer.py +++ b/artiq/gateware/rtio/analyzer.py @@ -3,6 +3,8 @@ from migen.genlib.record import Record, layout_len from misoc.interconnect.csr import * from misoc.interconnect import stream +from artiq.coredevice.analyzer import MessageType, ExceptionType + __all__ = ["Analyzer"] @@ -29,34 +31,10 @@ assert layout_len(input_output_layout) == 256 assert layout_len(exception_layout) == 256 -class MessageTypes(AutoCSR): - def __init__(self): - self.output = CSRConstant(0b00) - self.input = CSRConstant(0b01) - self.exception = CSRConstant(0b10) - - -class ExceptionTypes(AutoCSR): - def __init__(self): - self.reset_rising = CSRConstant(0b000000) - self.reset_falling = CSRConstant(0b000001) - self.reset_phy_rising = CSRConstant(0b000010) - self.reset_phy_falling = CSRConstant(0b000011) - - self.o_underflow_reset = CSRConstant(0b010000) - self.o_sequence_error_reset = CSRConstant(0b010001) - self.o_collision_error_reset = CSRConstant(0b010010) - - self.i_overflow_reset = CSRConstant(0b100000) - - class MessageEncoder(Module, AutoCSR): def __init__(self, rtio_core): self.source = stream.Endpoint([("data", 256)]) - self.message_types = MessageTypes() - self.exception_types = ExceptionTypes() - self.overflow = CSRStatus() self.overflow_reset = CSR() @@ -84,11 +62,11 @@ class MessageEncoder(Module, AutoCSR): input_output.rtio_counter.eq( rtio_core.counter.value_sys << rtio_core.fine_ts_width), If(kcsrs.o_we.re, - input_output.message_type.eq(self.message_types.output.value), + input_output.message_type.eq(MessageType.output.value), input_output.timestamp.eq(kcsrs.o_timestamp.storage), input_output.data.eq(o_data) ).Else( - input_output.message_type.eq(self.message_types.input.value), + input_output.message_type.eq(MessageType.input.value), input_output.timestamp.eq(kcsrs.i_timestamp.status), input_output.data.eq(i_data) ), @@ -98,7 +76,7 @@ class MessageEncoder(Module, AutoCSR): exception_stb = Signal() exception = Record(exception_layout) self.comb += [ - exception.message_type.eq(self.message_types.exception.value), + exception.message_type.eq(MessageType.exception.value), exception.channel.eq(kcsrs.chan_sel.storage), exception.rtio_counter.eq( rtio_core.counter.value_sys << rtio_core.fine_ts_width), @@ -109,7 +87,7 @@ class MessageEncoder(Module, AutoCSR): If(getattr(kcsrs, ename).re, exception_stb.eq(1), exception.exception_type.eq( - getattr(self.exception_types, ename).value) + getattr(ExceptionType, ename).value) ) for rname in "reset", "reset_phy": r_d = Signal() @@ -119,12 +97,12 @@ class MessageEncoder(Module, AutoCSR): If(r & ~r_d, exception_stb.eq(1), exception.exception_type.eq( - getattr(self.exception_types, rname+"_rising").value) + getattr(ExceptionType, rname+"_rising").value) ), If(~r & r_d, exception_stb.eq(1), exception.exception_type.eq( - getattr(self.exception_types, rname+"_falling").value) + getattr(ExceptionType, rname+"_falling").value) ) ]