forked from M-Labs/artiq
coredevice: analyzer message decoding
This commit is contained in:
parent
d5216879d4
commit
46f59b673f
|
@ -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
|
||||||
|
|
|
@ -5,27 +5,7 @@ import struct
|
||||||
|
|
||||||
from artiq.master.databases import DeviceDB
|
from artiq.master.databases import DeviceDB
|
||||||
from artiq.master.worker_db import DeviceManager
|
from artiq.master.worker_db import DeviceManager
|
||||||
|
from artiq.coredevice.analyzer import decode_dump
|
||||||
|
|
||||||
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:]
|
|
||||||
|
|
||||||
|
|
||||||
def get_argparser():
|
def get_argparser():
|
||||||
|
@ -100,7 +80,8 @@ def main():
|
||||||
comm.flash_storage_erase()
|
comm.flash_storage_erase()
|
||||||
elif args.action == "analyzer-dump":
|
elif args.action == "analyzer-dump":
|
||||||
dump = comm.get_analyzer_dump()
|
dump = comm.get_analyzer_dump()
|
||||||
print_analyzer_dump(dump)
|
for msg in decode_dump(dump):
|
||||||
|
print(msg)
|
||||||
finally:
|
finally:
|
||||||
device_mgr.close_devices()
|
device_mgr.close_devices()
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,8 @@ from migen.genlib.record import Record, layout_len
|
||||||
from misoc.interconnect.csr import *
|
from misoc.interconnect.csr import *
|
||||||
from misoc.interconnect import stream
|
from misoc.interconnect import stream
|
||||||
|
|
||||||
|
from artiq.coredevice.analyzer import MessageType, ExceptionType
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["Analyzer"]
|
__all__ = ["Analyzer"]
|
||||||
|
|
||||||
|
@ -29,34 +31,10 @@ assert layout_len(input_output_layout) == 256
|
||||||
assert layout_len(exception_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):
|
class MessageEncoder(Module, AutoCSR):
|
||||||
def __init__(self, rtio_core):
|
def __init__(self, rtio_core):
|
||||||
self.source = stream.Endpoint([("data", 256)])
|
self.source = stream.Endpoint([("data", 256)])
|
||||||
|
|
||||||
self.message_types = MessageTypes()
|
|
||||||
self.exception_types = ExceptionTypes()
|
|
||||||
|
|
||||||
self.overflow = CSRStatus()
|
self.overflow = CSRStatus()
|
||||||
self.overflow_reset = CSR()
|
self.overflow_reset = CSR()
|
||||||
|
|
||||||
|
@ -84,11 +62,11 @@ class MessageEncoder(Module, AutoCSR):
|
||||||
input_output.rtio_counter.eq(
|
input_output.rtio_counter.eq(
|
||||||
rtio_core.counter.value_sys << rtio_core.fine_ts_width),
|
rtio_core.counter.value_sys << rtio_core.fine_ts_width),
|
||||||
If(kcsrs.o_we.re,
|
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.timestamp.eq(kcsrs.o_timestamp.storage),
|
||||||
input_output.data.eq(o_data)
|
input_output.data.eq(o_data)
|
||||||
).Else(
|
).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.timestamp.eq(kcsrs.i_timestamp.status),
|
||||||
input_output.data.eq(i_data)
|
input_output.data.eq(i_data)
|
||||||
),
|
),
|
||||||
|
@ -98,7 +76,7 @@ class MessageEncoder(Module, AutoCSR):
|
||||||
exception_stb = Signal()
|
exception_stb = Signal()
|
||||||
exception = Record(exception_layout)
|
exception = Record(exception_layout)
|
||||||
self.comb += [
|
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.channel.eq(kcsrs.chan_sel.storage),
|
||||||
exception.rtio_counter.eq(
|
exception.rtio_counter.eq(
|
||||||
rtio_core.counter.value_sys << rtio_core.fine_ts_width),
|
rtio_core.counter.value_sys << rtio_core.fine_ts_width),
|
||||||
|
@ -109,7 +87,7 @@ class MessageEncoder(Module, AutoCSR):
|
||||||
If(getattr(kcsrs, ename).re,
|
If(getattr(kcsrs, ename).re,
|
||||||
exception_stb.eq(1),
|
exception_stb.eq(1),
|
||||||
exception.exception_type.eq(
|
exception.exception_type.eq(
|
||||||
getattr(self.exception_types, ename).value)
|
getattr(ExceptionType, ename).value)
|
||||||
)
|
)
|
||||||
for rname in "reset", "reset_phy":
|
for rname in "reset", "reset_phy":
|
||||||
r_d = Signal()
|
r_d = Signal()
|
||||||
|
@ -119,12 +97,12 @@ class MessageEncoder(Module, AutoCSR):
|
||||||
If(r & ~r_d,
|
If(r & ~r_d,
|
||||||
exception_stb.eq(1),
|
exception_stb.eq(1),
|
||||||
exception.exception_type.eq(
|
exception.exception_type.eq(
|
||||||
getattr(self.exception_types, rname+"_rising").value)
|
getattr(ExceptionType, rname+"_rising").value)
|
||||||
),
|
),
|
||||||
If(~r & r_d,
|
If(~r & r_d,
|
||||||
exception_stb.eq(1),
|
exception_stb.eq(1),
|
||||||
exception.exception_type.eq(
|
exception.exception_type.eq(
|
||||||
getattr(self.exception_types, rname+"_falling").value)
|
getattr(ExceptionType, rname+"_falling").value)
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue