diff --git a/artiq/gateware/drtio/rt_packet_repeater.py b/artiq/gateware/drtio/rt_packet_repeater.py index 9f5e513f9..081d444a3 100644 --- a/artiq/gateware/drtio/rt_packet_repeater.py +++ b/artiq/gateware/drtio/rt_packet_repeater.py @@ -18,8 +18,16 @@ class RTPacketRepeater(Module): self.err_packet_truncated = Signal() # in rtio domain + self.command_missed = Signal() self.buffer_space_timeout = Signal() + # set_time interface, in rtio domain + self.set_time_stb = Signal() + self.set_time_ack = Signal() + self.tsc_value = Signal(64) + + # # # + # RX/TX datapath assert len(link_layer.tx_rt_data) == len(link_layer.rx_rt_data) assert len(link_layer.tx_rt_data) % 8 == 0 @@ -33,6 +41,11 @@ class RTPacketRepeater(Module): link_layer.rx_rt_frame, link_layer.rx_rt_data, rx_plm)) self.submodules += rx_dp + # TSC sync + tsc_value = Signal(64) + tsc_value_load = Signal() + self.sync.rtio += If(tsc_value_load, tsc_value.eq(self.tsc_value)) + # Write buffer and extra data count wb_timestamp = Signal(64) wb_chan_sel = Signal(24) @@ -89,13 +102,30 @@ class RTPacketRepeater(Module): timeout_counter = ClockDomainsRenamer("rtio")(WaitTimer(8191)) self.submodules += timeout_counter + # Missed commands + cri_ready = Signal() + self.sync.rtio += self.command_missed.eq(~cri_ready & (self.cri.cmd != cri.commands["nop"])) + # TX FSM tx_fsm = ClockDomainsRenamer("rtio")(FSM(reset_state="IDLE")) self.submodules += tx_fsm tx_fsm.act("IDLE", - If(self.cri.cmd == cri.commands["write"], NextState("WRITE")), - If(self.cri.cmd == cri.commands["get_buffer_space"], NextState("BUFFER_SPACE")) + If(self.set_time_stb, + tsc_value_load.eq(1), + NextState("SET_TIME") + ).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")) + ) + ) + tx_fsm.act("SET_TIME", + tx_dp.send("set_time", timestamp=tsc_value), + If(tx_dp.packet_last, + self.set_time_ack.eq(1), + NextState("IDLE") + ) ) tx_fsm.act("WRITE", tx_dp.send("write", diff --git a/artiq/gateware/test/drtio/test_rt_packet_repeater.py b/artiq/gateware/test/drtio/test_rt_packet_repeater.py index bdc753853..c778d1724 100644 --- a/artiq/gateware/test/drtio/test_rt_packet_repeater.py +++ b/artiq/gateware/test/drtio/test_rt_packet_repeater.py @@ -19,6 +19,32 @@ def create_dut(nwords): class TestRepeater(unittest.TestCase): + def test_set_time(self): + nwords = 2 + pt, pr, dut = create_dut(nwords) + + def send(): + yield dut.tsc_value.eq(0x12345678) + yield dut.set_time_stb.eq(1) + while not (yield dut.set_time_ack): + yield + yield dut.set_time_stb.eq(0) + yield + for _ in range(30): + yield + + received = False + def receive(packet_type, field_dict, trailer): + nonlocal received + self.assertEqual(packet_type, "set_time") + self.assertEqual(trailer, []) + self.assertEqual(field_dict["timestamp"], 0x12345678) + self.assertEqual(received, False) + received = True + + run_simulation(dut, [send(), pr.receive(receive)]) + self.assertEqual(received, True) + def test_output(self): test_writes = [ (1, 10, 21, 0x42),