diff --git a/artiq/coredevice/analyzer.py b/artiq/coredevice/analyzer.py index f526bb2ec..b3db2637f 100644 --- a/artiq/coredevice/analyzer.py +++ b/artiq/coredevice/analyzer.py @@ -19,6 +19,9 @@ InputMessage = namedtuple( ExceptionMessage = namedtuple( "ExceptionMessage", "channel rtio_counter exception_type") +StoppedMessage = namedtuple( + "StoppedMessage", "rtio_counter") + def decode_message(data): message_type_channel = struct.unpack(">I", data[28:32])[0] @@ -37,6 +40,11 @@ def decode_message(data): exception_type, rtio_counter = struct.unpack(">BQ", data[11:20]) return ExceptionMessage(channel, rtio_counter, ExceptionType(exception_type)) + elif message_type == MessageType.stopped: + rtio_counter = struct.unpack(">Q", data[12:20])[0] + return StoppedMessage(rtio_counter) + else: + raise ValueError DecodedDump = namedtuple( diff --git a/artiq/gateware/rtio/analyzer.py b/artiq/gateware/rtio/analyzer.py index 3ccf6214a..6a1e6615e 100644 --- a/artiq/gateware/rtio/analyzer.py +++ b/artiq/gateware/rtio/analyzer.py @@ -27,13 +27,23 @@ exception_layout = [ ("padding1", 88) ] -assert layout_len(input_output_layout) == 256 -assert layout_len(exception_layout) == 256 +stopped_layout = [ + ("message_type", 2), + ("padding0", 94), + ("rtio_counter", 64), + ("padding1", 96) +] + +message_len = 256 + +assert layout_len(input_output_layout) == message_len +assert layout_len(exception_layout) == message_len +assert layout_len(stopped_layout) == message_len class MessageEncoder(Module, AutoCSR): - def __init__(self, rtio_core): - self.source = stream.Endpoint([("data", 256)]) + def __init__(self, rtio_core, enable): + self.source = stream.Endpoint([("data", message_len)]) self.overflow = CSRStatus() self.overflow_reset = CSR() @@ -106,19 +116,37 @@ class MessageEncoder(Module, AutoCSR): ) ] - self.sync += [ - If(exception_stb, - self.source.data.eq(exception.raw_bits()) - ).Else( - self.source.data.eq(input_output.raw_bits()) - ), - self.source.stb.eq(input_output_stb | exception_stb) + stopped = Record(stopped_layout) + self.comb += [ + stopped.message_type.eq(MessageType.stopped.value), + stopped.rtio_counter.eq( + rtio_core.counter.value_sys << rtio_core.fine_ts_width), ] + enable_r = Signal() + stopping = Signal() self.sync += [ - If(self.overflow_reset.re, self.overflow.status.eq(0)), - If(self.source.stb & ~self.source.ack, - self.overflow.status.eq(1) + enable_r.eq(enable), + If(~enable & enable_r, stopping.eq(1)), + + If(~stopping, + If(exception_stb, + self.source.data.eq(exception.raw_bits()) + ).Else( + self.source.data.eq(input_output.raw_bits()) + ), + self.source.stb.eq(enable & + (input_output_stb | exception_stb)), + + If(self.overflow_reset.re, self.overflow.status.eq(0)), + If(self.source.stb & ~self.source.ack, + self.overflow.status.eq(1) + ) + ).Else( + self.source.data.eq(stopped.raw_bits()), + self.source.eop.eq(1), + self.source.stb.eq(1), + If(self.source.ack, stopping.eq(0)) ) ] @@ -127,77 +155,86 @@ class DMAWriter(Module, AutoCSR): def __init__(self, membus): aw = len(membus.adr) dw = len(membus.dat_w) + messages_per_dw = dw//message_len data_alignment = log2_int(dw//8) - # shutdown procedure: set enable to 0, wait until busy=0 - self.enable = CSRStorage() - self.busy = CSRStatus() self.reset = CSR() # only apply when shut down # All numbers in bytes self.base_address = CSRStorage(aw + data_alignment, alignment_bits=data_alignment) self.last_address = CSRStorage(aw + data_alignment, alignment_bits=data_alignment) - self.byte_count = CSRStatus(64) # only read when shut down + self.byte_count = CSRStatus(32) # only read when shut down - self.sink = stream.Endpoint([("data", dw)]) + sink_layout = [("data", dw)] + if messages_per_dw > 1: + sink_layout.append(("valid_token_count", + bits_for(messages_per_dw))) + self.sink = stream.Endpoint(sink_layout) # # # - event_counter = Signal(63) - self.comb += self.byte_count.status.eq( - event_counter << data_alignment) + self.comb += [ + membus.stb.eq(self.sink.stb), + self.sink.ack.eq(membus.ack), + membus.we.eq(1), + membus.dat_w.eq(self.sink.data) + ] + if messages_per_dw > 1: + for i in range(dw//8): + self.comb += membus.sel[i].eq( + self.sink.valid_token_count >= i//(256//8)) + else: + self.comb += membus.sel.eq(2**(dw//8)-1) - fsm = FSM() - self.submodules += fsm - - fsm.act("IDLE", - If(self.enable.storage & self.sink.stb, - NextState("WRITE") - ), - If(~self.enable.storage, - self.sink.ack.eq(1) - ), + self.sync += [ If(self.reset.re, - NextValue(membus.adr, self.base_address.storage), - NextValue(event_counter, 0) - ) - ) - fsm.act("WRITE", - self.busy.status.eq(1), - membus.cyc.eq(1), - membus.stb.eq(1), - + membus.adr.eq(self.base_address.storage)), If(membus.ack, If(membus.adr == self.last_address.storage, - NextValue(membus.adr, self.base_address.storage) + membus.adr.eq(self.base_address.storage) ).Else( - NextValue(membus.adr, membus.adr + 1) + membus.adr.eq(membus.adr + 1) ), - NextValue(event_counter, event_counter + 1), - self.sink.ack.eq(1), - NextState("IDLE") ) - ) - self.comb += [ - membus.we.eq(1), - membus.sel.eq(2**len(membus.sel)-1), - membus.dat_w.eq(self.sink.data) + ] + + event_counter = Signal(32) + self.comb += self.byte_count.status.eq( + event_counter << data_alignment) + self.sync += [ + If(self.reset.re, event_counter.eq(0)), + If(membus.ack, event_counter.eq(event_counter + 1)) ] class Analyzer(Module, AutoCSR): def __init__(self, rtio_core, membus, fifo_depth=128): - dw = len(membus.dat_w) + # shutdown procedure: set enable to 0, wait until busy=0 + self.enable = CSRStorage() + self.busy = CSRStatus() - self.submodules.message_encoder = MessageEncoder(rtio_core) - self.submodules.converter = stream.Converter(256, dw, reverse=True) + self.submodules.message_encoder = MessageEncoder( + rtio_core, self.enable.storage) self.submodules.fifo = stream.SyncFIFO( - [("data", dw)], fifo_depth, True) + [("data", message_len)], fifo_depth, True) + dw = len(membus.dat_w) + self.submodules.converter = stream.Converter( + message_len, dw, reverse=True, + report_valid_token_count=dw > message_len) self.submodules.dma = DMAWriter(membus) - self.comb += [ - self.message_encoder.source.connect(self.converter.sink), - self.converter.source.connect(self.fifo.sink), - self.fifo.source.connect(self.dma.sink) + enable_r = Signal() + self.sync += [ + enable_r.eq(self.enable.storage), + If(self.enable.storage & ~enable_r, + self.busy.status.eq(1)), + If(self.dma.sink.stb & self.dma.sink.ack & self.dma.sink.eop, + self.busy.status.eq(0)) + ] + + self.comb += [ + self.message_encoder.source.connect(self.fifo.sink), + self.fifo.source.connect(self.converter.sink), + self.converter.source.connect(self.dma.sink) ] diff --git a/artiq/protocols/analyzer.py b/artiq/protocols/analyzer.py index 46ca712ee..e3ec7da7b 100644 --- a/artiq/protocols/analyzer.py +++ b/artiq/protocols/analyzer.py @@ -5,6 +5,7 @@ class MessageType(Enum): output = 0b00 input = 0b01 exception = 0b10 + stopped = 0b11 class ExceptionType(Enum): diff --git a/artiq/runtime/analyzer.c b/artiq/runtime/analyzer.c index 23f77c98d..feeffac2c 100644 --- a/artiq/runtime/analyzer.c +++ b/artiq/runtime/analyzer.c @@ -27,13 +27,13 @@ static void arm(void) rtio_analyzer_dma_base_address_write((unsigned int)analyzer_buffer); rtio_analyzer_dma_last_address_write((unsigned int)analyzer_buffer + ANALYZER_BUFFER_SIZE - 1); rtio_analyzer_dma_reset_write(1); - rtio_analyzer_dma_enable_write(1); + rtio_analyzer_enable_write(1); } static void disarm(void) { - rtio_analyzer_dma_enable_write(0); - while(rtio_analyzer_dma_busy_read()); + rtio_analyzer_enable_write(0); + while(rtio_analyzer_busy_read()); flush_cpu_dcache(); flush_l2_cache(); }