forked from M-Labs/artiq
drtio: add TSC sync and missed command detection to rt_packet_repeater
This commit is contained in:
parent
00fabee1ca
commit
778f1de121
|
@ -18,8 +18,16 @@ class RTPacketRepeater(Module):
|
||||||
self.err_packet_truncated = Signal()
|
self.err_packet_truncated = Signal()
|
||||||
|
|
||||||
# in rtio domain
|
# in rtio domain
|
||||||
|
self.command_missed = Signal()
|
||||||
self.buffer_space_timeout = 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
|
# RX/TX datapath
|
||||||
assert len(link_layer.tx_rt_data) == len(link_layer.rx_rt_data)
|
assert len(link_layer.tx_rt_data) == len(link_layer.rx_rt_data)
|
||||||
assert len(link_layer.tx_rt_data) % 8 == 0
|
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))
|
link_layer.rx_rt_frame, link_layer.rx_rt_data, rx_plm))
|
||||||
self.submodules += rx_dp
|
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
|
# Write buffer and extra data count
|
||||||
wb_timestamp = Signal(64)
|
wb_timestamp = Signal(64)
|
||||||
wb_chan_sel = Signal(24)
|
wb_chan_sel = Signal(24)
|
||||||
|
@ -89,13 +102,30 @@ class RTPacketRepeater(Module):
|
||||||
timeout_counter = ClockDomainsRenamer("rtio")(WaitTimer(8191))
|
timeout_counter = ClockDomainsRenamer("rtio")(WaitTimer(8191))
|
||||||
self.submodules += timeout_counter
|
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
|
||||||
tx_fsm = ClockDomainsRenamer("rtio")(FSM(reset_state="IDLE"))
|
tx_fsm = ClockDomainsRenamer("rtio")(FSM(reset_state="IDLE"))
|
||||||
self.submodules += tx_fsm
|
self.submodules += tx_fsm
|
||||||
|
|
||||||
tx_fsm.act("IDLE",
|
tx_fsm.act("IDLE",
|
||||||
If(self.cri.cmd == cri.commands["write"], NextState("WRITE")),
|
If(self.set_time_stb,
|
||||||
If(self.cri.cmd == cri.commands["get_buffer_space"], NextState("BUFFER_SPACE"))
|
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_fsm.act("WRITE",
|
||||||
tx_dp.send("write",
|
tx_dp.send("write",
|
||||||
|
|
|
@ -19,6 +19,32 @@ def create_dut(nwords):
|
||||||
|
|
||||||
|
|
||||||
class TestRepeater(unittest.TestCase):
|
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):
|
def test_output(self):
|
||||||
test_writes = [
|
test_writes = [
|
||||||
(1, 10, 21, 0x42),
|
(1, 10, 21, 0x42),
|
||||||
|
|
Loading…
Reference in New Issue