From 2b44786f73c7f0619ecf80d4e48a7d608187aa3f Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 17 Sep 2018 23:45:27 +0800 Subject: [PATCH] drtio: add repeater input support --- artiq/gateware/drtio/rt_packet_repeater.py | 102 ++++++++++++++++-- .../test/drtio/test_rt_packet_repeater.py | 62 +++++++++++ 2 files changed, 158 insertions(+), 6 deletions(-) diff --git a/artiq/gateware/drtio/rt_packet_repeater.py b/artiq/gateware/drtio/rt_packet_repeater.py index 7f709589f..150704f75 100644 --- a/artiq/gateware/drtio/rt_packet_repeater.py +++ b/artiq/gateware/drtio/rt_packet_repeater.py @@ -103,6 +103,61 @@ class RTPacketRepeater(Module): timeout_counter = ClockDomainsRenamer("rtio")(WaitTimer(8191)) self.submodules += timeout_counter + # Read + rb_chan_sel = Signal(24) + rb_timeout = Signal(64) + self.sync.rtio += If(self.cri.cmd == cri.commands["read"], + rb_chan_sel.eq(self.cri.chan_sel), + rb_timeout.eq(self.cri.timestamp)) + + read_not = Signal() + read_no_event = Signal() + read_is_overflow = Signal() + read_data = Signal(32) + read_timestamp = Signal(64) + rtio_read_not = Signal() + rtio_read_not_ack = Signal() + rtio_read_no_event = Signal() + rtio_read_is_overflow = Signal() + rtio_read_data = Signal(32) + rtio_read_timestamp = Signal(64) + self.submodules += CrossDomainNotification("rtio_rx", "rtio", + read_not, + Cat(read_no_event, read_is_overflow, read_data, read_timestamp), + + rtio_read_not, rtio_read_not_ack, + Cat(rtio_read_no_event, rtio_read_is_overflow, + rtio_read_data, rtio_read_timestamp)) + self.comb += [ + read_is_overflow.eq(rx_dp.packet_as["read_reply_noevent"].overflow), + read_data.eq(rx_dp.packet_as["read_reply"].data), + read_timestamp.eq(rx_dp.packet_as["read_reply"].timestamp) + ] + + # input status + i_status_wait_event = Signal() + i_status_overflow = Signal() + i_status_wait_status = Signal() + self.comb += self.cri.i_status.eq(Cat( + i_status_wait_event, i_status_overflow, i_status_wait_status)) + + load_read_reply = Signal() + self.sync.rtio += [ + If(load_read_reply, + i_status_wait_event.eq(0), + i_status_overflow.eq(0), + If(rtio_read_no_event, + If(rtio_read_is_overflow, + i_status_overflow.eq(1) + ).Else( + i_status_wait_event.eq(1) + ) + ), + self.cri.i_data.eq(rtio_read_data), + self.cri.i_timestamp.eq(rtio_read_timestamp) + ) + ] + # Missed commands cri_ready = Signal() self.sync.rtio += [ @@ -111,7 +166,7 @@ class RTPacketRepeater(Module): self.command_missed_cmd.eq(self.cri.cmd) ] - # TX FSM + # TX and CRI FSM tx_fsm = ClockDomainsRenamer("rtio")(FSM(reset_state="IDLE")) self.submodules += tx_fsm @@ -126,9 +181,11 @@ class RTPacketRepeater(Module): ).Else( cri_ready.eq(1), If(self.cri.cmd == cri.commands["write"], NextState("WRITE")), - If(self.cri.cmd == cri.commands["get_buffer_space"], NextState("BUFFER_SPACE")) + If(self.cri.cmd == cri.commands["get_buffer_space"], NextState("BUFFER_SPACE")), + If(self.cri.cmd == cri.commands["read"], NextState("READ")) ) ) + tx_fsm.act("SET_TIME", tx_dp.send("set_time", timestamp=tsc_value), If(tx_dp.packet_last, @@ -136,6 +193,7 @@ class RTPacketRepeater(Module): NextState("IDLE") ) ) + tx_fsm.act("WRITE", tx_dp.send("write", timestamp=wb_timestamp, @@ -158,26 +216,46 @@ class RTPacketRepeater(Module): NextState("IDLE") ) ) + tx_fsm.act("BUFFER_SPACE", tx_dp.send("buffer_space_request", destination=self.buffer_space_destination), If(tx_dp.packet_last, buffer_space_not_ack.eq(1), - NextState("WAIT_BUFFER_SPACE") + NextState("GET_BUFFER_SPACE_REPLY") ) ) - tx_fsm.act("WAIT_BUFFER_SPACE", + tx_fsm.act("GET_BUFFER_SPACE_REPLY", timeout_counter.wait.eq(1), If(timeout_counter.done, self.err_buffer_space_timeout.eq(1), - NextState("IDLE") + NextState("READY") ).Else( If(buffer_space_not, self.cri.o_buffer_space_valid.eq(1), - NextState("IDLE") + NextState("READY") ), ) ) + tx_fsm.act("READ", + i_status_wait_status.eq(1), + tx_dp.send("read_request", + chan_sel=rb_chan_sel, + timeout=rb_timeout), + rtio_read_not_ack.eq(1), + If(tx_dp.packet_last, + NextState("GET_READ_REPLY") + ) + ) + tx_fsm.act("GET_READ_REPLY", + i_status_wait_status.eq(1), + rtio_read_not_ack.eq(1), + If(rtio_read_not, + load_read_reply.eq(1), + NextState("READY") + ) + ) + # RX FSM rx_fsm = ClockDomainsRenamer("rtio_rx")(FSM(reset_state="INPUT")) self.submodules += rx_fsm @@ -192,6 +270,8 @@ class RTPacketRepeater(Module): If(rx_dp.packet_last, Case(rx_dp.packet_type, { rx_plm.types["buffer_space_reply"]: NextState("BUFFER_SPACE"), + rx_plm.types["read_reply"]: NextState("READ_REPLY"), + rx_plm.types["read_reply_noevent"]: NextState("READ_REPLY_NOEVENT"), "default": self.err_unknown_packet_type.eq(1) }) ).Else( @@ -207,3 +287,13 @@ class RTPacketRepeater(Module): rx_buffer_space.eq(rx_dp.packet_as["buffer_space_reply"].space), NextState("INPUT") ) + rx_fsm.act("READ_REPLY", + read_not.eq(1), + read_no_event.eq(0), + NextState("INPUT") + ) + rx_fsm.act("READ_REPLY_NOEVENT", + read_not.eq(1), + read_no_event.eq(1), + NextState("INPUT") + ) diff --git a/artiq/gateware/test/drtio/test_rt_packet_repeater.py b/artiq/gateware/test/drtio/test_rt_packet_repeater.py index 70f25adb0..0bf80eb3d 100644 --- a/artiq/gateware/test/drtio/test_rt_packet_repeater.py +++ b/artiq/gateware/test/drtio/test_rt_packet_repeater.py @@ -128,3 +128,65 @@ class TestRepeater(unittest.TestCase): current_request = field_dict["destination"] run_simulation(dut, [send_requests(), send_replies(), pr.receive(receive)]) + + def test_input(self): + for nwords in range(1, 8): + pt, pr, ts, dut = create_dut(nwords) + + def read(chan_sel, timeout): + yield dut.cri.chan_sel.eq(chan_sel) + yield dut.cri.timestamp.eq(timeout) + yield dut.cri.cmd.eq(cri.commands["read"]) + yield + yield dut.cri.cmd.eq(cri.commands["nop"]) + yield + status = yield dut.cri.i_status + while status & 4: + yield + status = yield dut.cri.i_status + if status & 0x1: + return "timeout" + if status & 0x2: + return "overflow" + if status & 0x8: + return "destination unreachable" + return ((yield dut.cri.i_data), + (yield dut.cri.i_timestamp)) + + def send_requests(): + for timeout in range(20, 200000, 100000): + for chan_sel in range(3): + data, timestamp = yield from read(chan_sel, timeout) + self.assertEqual(data, chan_sel*2) + self.assertEqual(timestamp, timeout//2) + + i2 = yield from read(10, 400000) + self.assertEqual(i2, "timeout") + i3 = yield from read(11, 400000) + self.assertEqual(i3, "overflow") + + current_request = None + + @passive + def send_replies(): + nonlocal current_request + while True: + while current_request is None: + yield + chan_sel, timeout = current_request + if chan_sel == 10: + yield from pt.send("read_reply_noevent", overflow=0) + elif chan_sel == 11: + yield from pt.send("read_reply_noevent", overflow=1) + else: + yield from pt.send("read_reply", data=chan_sel*2, timestamp=timeout//2) + current_request = None + + def receive(packet_type, field_dict, trailer): + nonlocal current_request + self.assertEqual(packet_type, "read_request") + self.assertEqual(trailer, []) + self.assertEqual(current_request, None) + current_request = (field_dict["chan_sel"], field_dict["timeout"]) + + run_simulation(dut, [send_requests(), send_replies(), pr.receive(receive)])