From 497c795d8c067849c0f64a9497dbb3639fbfda89 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Mon, 13 Mar 2017 23:54:44 +0800 Subject: [PATCH] drtio: input support (untested) --- artiq/gateware/drtio/rt_controller_master.py | 91 ++++++--- artiq/gateware/drtio/rt_ios_satellite.py | 197 +++++++++++++------ artiq/gateware/drtio/rt_packet_master.py | 58 +++++- artiq/gateware/drtio/rt_packet_satellite.py | 18 +- artiq/gateware/drtio/rt_serializer.py | 1 - artiq/gateware/rtio/cri.py | 2 +- 6 files changed, 265 insertions(+), 102 deletions(-) diff --git a/artiq/gateware/drtio/rt_controller_master.py b/artiq/gateware/drtio/rt_controller_master.py index afccdb94d..d9186a498 100644 --- a/artiq/gateware/drtio/rt_controller_master.py +++ b/artiq/gateware/drtio/rt_controller_master.py @@ -96,6 +96,7 @@ class RTController(Module): # common packet fields rt_packet_fifo_request = Signal() + rt_packet_read_request = Signal() self.comb += [ fifo_spaces.adr.eq(chan_sel), last_timestamps.adr.eq(chan_sel), @@ -107,27 +108,29 @@ class RTController(Module): If(rt_packet_fifo_request, rt_packet.sr_notwrite.eq(1), rt_packet.sr_address.eq(0) + ), + If(rt_packet_read_request, + rt_packet.sr_notwrite.eq(1), + rt_packet.sr_address.eq(1) ) ] - fsm = ClockDomainsRenamer("sys_with_rst")(FSM()) - self.submodules += fsm - - status_wait = Signal() - status_underflow = Signal() - status_sequence_error = Signal() + # output status + o_status_wait = Signal() + o_status_underflow = Signal() + o_status_sequence_error = Signal() self.comb += [ self.cri.o_status.eq(Cat( - status_wait, status_underflow, status_sequence_error)), - self.csrs.o_wait.status.eq(status_wait) + o_status_wait, o_status_underflow, o_status_sequence_error)), + self.csrs.o_wait.status.eq(o_status_wait) ] - sequence_error_set = Signal() - underflow_set = Signal() + o_sequence_error_set = Signal() + o_underflow_set = Signal() self.sync.sys_with_rst += [ - If(self.cri.cmd == cri.commands["o_underflow_reset"], status_underflow.eq(0)), - If(self.cri.cmd == cri.commands["o_sequence_error_reset"], status_sequence_error.eq(0)), - If(underflow_set, status_underflow.eq(1)), - If(sequence_error_set, status_sequence_error.eq(1)) + If(self.cri.cmd == cri.commands["o_underflow_reset"], o_status_underflow.eq(0)), + If(self.cri.cmd == cri.commands["o_sequence_error_reset"], o_status_sequence_error.eq(0)), + If(o_underflow_set, o_status_underflow.eq(1)), + If(o_sequence_error_set, o_status_sequence_error.eq(1)) ] signal_fifo_space_timeout = Signal() @@ -143,22 +146,49 @@ class RTController(Module): cond_underflow = ((self.cri.timestamp[fine_ts_width:] - self.csrs.underflow_margin.storage[fine_ts_width:]) < self.counter.value_sys) + # 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.sys_with_rst += [ + If(load_read_reply, + i_status_wait_event.eq(0), + i_status_overflow.eq(0), + If(rt_packet.read_no_event, + If(rt_packet.read_is_overflow, + i_status_overflow.eq(1) + ).Else( + i_status_wait_event.eq(1) + ) + ), + self.cri.i_data.eq(rt_packet.read_data), + self.cri.i_timestamp.eq(rt_packet.read_timestamp) + ) + ] + + # FSM + fsm = ClockDomainsRenamer("sys_with_rst")(FSM()) + self.submodules += fsm + fsm.act("IDLE", If(self.cri.cmd == cri.commands["write"], If(cond_sequence_error, - sequence_error_set.eq(1) + o_sequence_error_set.eq(1) ).Elif(cond_underflow, - underflow_set.eq(1) + o_underflow_set.eq(1) ).Else( NextState("WRITE") ) ), - If(self.csrs.o_get_fifo_space.re, - NextState("GET_FIFO_SPACE") - ) + If(self.cri.cmd == cri.commands["read_request"], NextState("READ")), + If(self.csrs.o_get_fifo_space.re, NextState("GET_FIFO_SPACE")) ) fsm.act("WRITE", - status_wait.eq(1), + o_status_wait.eq(1), rt_packet.sr_stb.eq(1), If(rt_packet.sr_ack, fifo_spaces.we.eq(1), @@ -172,16 +202,16 @@ class RTController(Module): ) ) fsm.act("GET_FIFO_SPACE", - status_wait.eq(1), + o_status_wait.eq(1), + rt_packet.fifo_space_not_ack.eq(1), rt_packet_fifo_request.eq(1), rt_packet.sr_stb.eq(1), - rt_packet.fifo_space_not_ack.eq(1), If(rt_packet.sr_ack, NextState("GET_FIFO_SPACE_REPLY") ) ) fsm.act("GET_FIFO_SPACE_REPLY", - status_wait.eq(1), + o_status_wait.eq(1), fifo_spaces.dat_w.eq(rt_packet.fifo_space), fifo_spaces.we.eq(1), rt_packet.fifo_space_not_ack.eq(1), @@ -198,6 +228,21 @@ class RTController(Module): NextState("GET_FIFO_SPACE") ) ) + fsm.act("READ", + i_status_wait_status.eq(1), + rt_packet_read_request.eq(1), + rt_packet.sr_stb.eq(1), + If(rt_packet.sr_ack, + NextState("GET_READ_REPLY") + ) + ) + fsm.act("GET_READ_REPLY", + i_status_wait_status.eq(1), + If(rt_packet.read_not, + load_read_reply.eq(1), + NextState("IDLE") + ) + ) # channel state access self.comb += [ diff --git a/artiq/gateware/drtio/rt_ios_satellite.py b/artiq/gateware/drtio/rt_ios_satellite.py index 24e780533..1bba99977 100644 --- a/artiq/gateware/drtio/rt_ios_satellite.py +++ b/artiq/gateware/drtio/rt_ios_satellite.py @@ -9,81 +9,148 @@ from artiq.gateware.rtio import rtlink class IOS(Module): def __init__(self, rt_packet, channels, max_fine_ts_width, full_ts_width): - tsc = Signal(full_ts_width - max_fine_ts_width) + self.rt_packet = rt_packet + self.max_fine_ts_width = max_fine_ts_width + + self.tsc = Signal(full_ts_width - max_fine_ts_width) self.sync.rtio += \ If(rt_packet.tsc_load, - tsc.eq(rt_packet.tsc_load_value) + self.tsc.eq(rt_packet.tsc_load_value) ).Else( - tsc.eq(tsc + 1) + self.tsc.eq(self.tsc + 1) ) - self.comb += rt_packet.tsc_input.eq(tsc) + self.comb += rt_packet.tsc_input.eq(self.tsc) for n, channel in enumerate(channels): - interface = channel.interface.o - data_width = rtlink.get_data_width(interface) - address_width = rtlink.get_address_width(interface) - fine_ts_width = rtlink.get_fine_ts_width(interface) - assert fine_ts_width <= max_fine_ts_width + self.add_output(n, channel) + self.add_input(n, channel) - # FIFO - ev_layout = [] - if data_width: - ev_layout.append(("data", data_width)) - if address_width: - ev_layout.append(("address", address_width)) - ev_layout.append(("timestamp", len(tsc) + fine_ts_width)) + def add_output(self, n, channel): + rt_packet = self.rt_packet + max_fine_ts_width = self.max_fine_ts_width - fifo = ClockDomainsRenamer("rio")( - SyncFIFOBuffered(layout_len(ev_layout), channel.ofifo_depth)) - self.submodules += fifo - fifo_in = Record(ev_layout) - fifo_out = Record(ev_layout) - self.comb += [ - fifo.din.eq(fifo_in.raw_bits()), - fifo_out.raw_bits().eq(fifo.dout) - ] + interface = channel.interface.o + data_width = rtlink.get_data_width(interface) + address_width = rtlink.get_address_width(interface) + fine_ts_width = rtlink.get_fine_ts_width(interface) + assert fine_ts_width <= max_fine_ts_width - # FIFO level - self.sync.rio += \ - If(rt_packet.fifo_space_update & - (rt_packet.fifo_space_channel == n), - rt_packet.fifo_space.eq(channel.ofifo_depth - fifo.level)) + # FIFO + ev_layout = [] + if data_width: + ev_layout.append(("data", data_width)) + if address_width: + ev_layout.append(("address", address_width)) + ev_layout.append(("timestamp", len(self.tsc) + fine_ts_width)) - # FIFO write - self.comb += fifo.we.eq(rt_packet.write_stb - & (rt_packet.write_channel == n)) - self.sync.rio += [ - If(rt_packet.write_overflow_ack, - rt_packet.write_overflow.eq(0)), - If(rt_packet.write_underflow_ack, - rt_packet.write_underflow.eq(0)), - If(fifo.we, - If(~fifo.writable, rt_packet.write_overflow.eq(1)), - If(rt_packet.write_timestamp[max_fine_ts_width:] < (tsc + 4), - rt_packet.write_underflow.eq(1) - ) + fifo = ClockDomainsRenamer("rio")( + SyncFIFOBuffered(layout_len(ev_layout), channel.ofifo_depth)) + self.submodules += fifo + fifo_in = Record(ev_layout) + fifo_out = Record(ev_layout) + self.comb += [ + fifo.din.eq(fifo_in.raw_bits()), + fifo_out.raw_bits().eq(fifo.dout) + ] + + # FIFO level + self.sync.rio += \ + If(rt_packet.fifo_space_update & + (rt_packet.fifo_space_channel == n), + rt_packet.fifo_space.eq(channel.ofifo_depth - fifo.level)) + + # FIFO write + self.comb += fifo.we.eq(rt_packet.write_stb + & (rt_packet.write_channel == n)) + self.sync.rio += [ + If(rt_packet.write_overflow_ack, + rt_packet.write_overflow.eq(0)), + If(rt_packet.write_underflow_ack, + rt_packet.write_underflow.eq(0)), + If(fifo.we, + If(~fifo.writable, rt_packet.write_overflow.eq(1)), + If(rt_packet.write_timestamp[max_fine_ts_width:] < (self.tsc + 4), + rt_packet.write_underflow.eq(1) ) - ] - if data_width: - self.comb += fifo_in.data.eq(rt_packet.write_data) - if address_width: - self.comb += fifo_in.address.eq(rt_packet.write_address) - self.comb += fifo_in.timestamp.eq( - rt_packet.write_timestamp[max_fine_ts_width-fine_ts_width:]) + ) + ] + if data_width: + self.comb += fifo_in.data.eq(rt_packet.write_data) + if address_width: + self.comb += fifo_in.address.eq(rt_packet.write_address) + self.comb += fifo_in.timestamp.eq( + rt_packet.write_timestamp[max_fine_ts_width-fine_ts_width:]) - # FIFO read - self.sync.rio += [ - fifo.re.eq(0), - interface.stb.eq(0), - If(fifo.readable & - (fifo_out.timestamp[fine_ts_width:] == tsc), - fifo.re.eq(1), - interface.stb.eq(1) - ) - ] - if data_width: - self.sync.rio += interface.data.eq(fifo_out.data) - if address_width: - self.sync.rio += interface.address.eq(fifo_out.address) + # FIFO read + self.sync.rio += [ + fifo.re.eq(0), + interface.stb.eq(0), + If(fifo.readable & + (fifo_out.timestamp[fine_ts_width:] == self.tsc), + fifo.re.eq(1), + interface.stb.eq(1) + ) + ] + if data_width: + self.sync.rio += interface.data.eq(fifo_out.data) + if address_width: + self.sync.rio += interface.address.eq(fifo_out.address) + if fine_ts_width: + self.sync.rio += interface.fine_ts.eq(fifo_out.timestamp[:fine_ts_width]) + + def add_input(self, n, channel): + interface = channel.interface.i + if interface is None: + return + data_width = rtlink.get_data_width(interface) + fine_ts_width = rtlink.get_fine_ts_width(interface) + + selected = Signal() + self.comb += selected.eq(rt_packet.read_channel == n) + + # FIFO + ev_layout = [] + if data_width: + ev_layout.append(("data", data_width)) + if interface.timestamped: + ev_layout.append(("timestamp", len(self.tsc) + fine_ts_width)) + + fifo = ClockDomainsRenamer("rio")( + SyncFIFOBuffered(layout_len(ev_layout), channel.ififo_depth)) + self.submodules += fifo + fifo_in = Record(ev_layout) + fifo_out = Record(ev_layout) + self.comb += [ + fifo.din.eq(fifo_in.raw_bits()), + fifo_out.raw_bits().eq(fifo.dout) + ] + + # FIFO write + if data_width: + self.comb += fifo_in.data.eq(interface.data) + if interface.timestamped: if fine_ts_width: - self.sync.rio += interface.fine_ts.eq(fifo_out.timestamp[:fine_ts_width]) + full_ts = Cat(interface.fine_ts, self.tsc) + else: + full_ts = self.tsc + self.comb += fifo_in.timestamp.eq(full_ts) + self.comb += fifo.we.eq(interface.stb) + + overflow = Signal() + self.comb += If(selected, rt_packet.read_overflow.eq(overflow)) + self.sync.rio += [ + If(selected & rt_packet.read_overflow_ack, overflow.eq(0)), + If(fifo.we & ~fifo.writable, overflow.eq(1)) + ] + + # FIFO read + if data_width: + self.comb += If(selected, rt_packet.read_data.eq(fifo_out.data)) + if interface.timestamped: + self.comb += If(selected, rt_packet.read_timestamp.eq(fifo_out.timestamp)) + self.comb += [ + If(selected, + rt_packet.read_readable.eq(fifo.readable), + fifo.re.eq(rt_packet.read_consume) + ) + ] diff --git a/artiq/gateware/drtio/rt_packet_master.py b/artiq/gateware/drtio/rt_packet_master.py index 3cf281b1a..b07ce23a1 100644 --- a/artiq/gateware/drtio/rt_packet_master.py +++ b/artiq/gateware/drtio/rt_packet_master.py @@ -43,7 +43,7 @@ class _CrossDomainNotification(Module): def __init__(self, domain, emi_stb, emi_data, rec_stb, rec_ack, rec_data): - emi_data_r = Signal.like(emi_data) + emi_data_r = Signal(len(emi_data)) emi_data_r.attr.add("no_retiming") dsync = getattr(self.sync, domain) dsync += If(emi_stb, emi_data_r.eq(emi_data)) @@ -68,7 +68,6 @@ class RTPacketMaster(Module): # # notwrite=1 address=0 FIFO space request # notwrite=1 address=1 read request - # notwrite=1 address=2 read consume # # optimized for write throughput # requests are performed on the DRTIO link preserving their order of issue @@ -87,6 +86,18 @@ class RTPacketMaster(Module): self.fifo_space_not_ack = Signal() self.fifo_space = Signal(16) + # read reply interface + self.read_not = Signal() + self.read_not_ack = Signal() + # no_event is_overflow + # 0 X event + # 1 0 timeout + # 1 1 overflow + self.read_no_event = Signal() + self.read_is_overflow = Signal() + self.read_data = Signal(32) + self.read_timestamp = Signal(64) + # echo interface self.echo_stb = Signal() self.echo_ack = Signal() @@ -230,6 +241,24 @@ class RTPacketMaster(Module): error_not, error_code, self.error_not, self.error_not_ack, self.error_code) + read_not = Signal() + read_no_event = Signal() + read_is_overflow = Signal() + read_data = Signal(32) + read_timestamp = Signal(64) + self.submodules += _CrossDomainNotification("rtio_rx", + read_not, + Cat(read_no_event, read_is_overflow, read_data, read_timestamp), + + self.read_not, self.read_not_ack, + Cat(self.read_no_event, self.read_is_overflow, + self.read_data, self.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) + ] + # TX FSM tx_fsm = ClockDomainsRenamer("rtio")(FSM(reset_state="IDLE")) self.submodules += tx_fsm @@ -243,8 +272,10 @@ class RTPacketMaster(Module): tx_fsm.act("IDLE", If(sr_buf_readable, If(sr_notwrite, - # TODO: sr_address - NextState("FIFO_SPACE") + Case(sr_address[0], { + 0: NextState("FIFO_SPACE"), + 1: NextState("READ") + }), ).Else( NextState("WRITE") ) @@ -291,6 +322,13 @@ class RTPacketMaster(Module): NextState("IDLE") ) ) + tx_fsm.act("READ", + tx_dp.send("read_request", channel=sr_channel, timeout=sr_timestamp), + If(tx_dp.packet_last, + sr_buf_re.eq(1), + NextState("IDLE") + ) + ) tx_fsm.act("ECHO", tx_dp.send("echo_request"), If(tx_dp.packet_last, @@ -332,6 +370,8 @@ class RTPacketMaster(Module): rx_plm.types["error"]: NextState("ERROR"), rx_plm.types["echo_reply"]: echo_received_now.eq(1), rx_plm.types["fifo_space_reply"]: NextState("FIFO_SPACE"), + rx_plm.types["read_reply"]: NextState("READ_REPLY"), + rx_plm.types["read_reply_noevent"]: NextState("READ_REPLY_NOEVENT"), "default": [ error_not.eq(1), error_code.eq(error_codes["unknown_type_local"]) @@ -356,6 +396,16 @@ class RTPacketMaster(Module): fifo_space.eq(rx_dp.packet_as["fifo_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") + ) # packet counters tx_frame_r = Signal() diff --git a/artiq/gateware/drtio/rt_packet_satellite.py b/artiq/gateware/drtio/rt_packet_satellite.py index 1234146e8..9faeeea65 100644 --- a/artiq/gateware/drtio/rt_packet_satellite.py +++ b/artiq/gateware/drtio/rt_packet_satellite.py @@ -32,9 +32,10 @@ class RTPacketSatellite(Module): self.read_channel = Signal(16) self.read_readable = Signal() self.read_consume = Signal() - self.read_timestamp = Signal(64) self.read_data = Signal(32) + self.read_timestamp = Signal(64) self.read_overflow = Signal() + self.read_overflow_ack = Signal() # # # @@ -144,7 +145,6 @@ class RTPacketSatellite(Module): rx_plm.types["write"]: NextState("WRITE"), rx_plm.types["fifo_space_request"]: NextState("FIFO_SPACE"), rx_plm.types["read_request"]: NextState("READ_REQUEST"), - rx_plm.types["read_consume"]: NextState("READ_CONSUME"), "default": [ err_set.eq(1), NextValue(err_code, error_codes["unknown_type_remote"])] @@ -194,10 +194,6 @@ class RTPacketSatellite(Module): load_read_request.eq(1), NextState("INPUT") ) - rx_fsm.act("READ_CONSUME", - self.read_consume.eq(1), - NextState("INPUT") - ) # TX FSM tx_fsm = FSM(reset_state="IDLE") @@ -245,14 +241,20 @@ class RTPacketSatellite(Module): tx_fsm.act("READ_OVERFLOW", tx_dp.send("read_reply_noevent", overflow=1), clear_read_request.eq(1), - If(tx_dp.packet_last, NextState("IDLE")) + If(tx_dp.packet_last, + self.read_overflow_ack.eq(1), + NextState("IDLE") + ) ) tx_fsm.act("READ", tx_dp.send("read_reply", timestamp=self.read_timestamp, data=self.read_data), clear_read_request.eq(1), - If(tx_dp.packet_last, NextState("IDLE")) + If(tx_dp.packet_last, + self.read_consume.eq(1), + NextState("IDLE") + ) ) tx_fsm.act("ERROR", diff --git a/artiq/gateware/drtio/rt_serializer.py b/artiq/gateware/drtio/rt_serializer.py index 9b5c16d15..6b61bd239 100644 --- a/artiq/gateware/drtio/rt_serializer.py +++ b/artiq/gateware/drtio/rt_serializer.py @@ -57,7 +57,6 @@ def get_m2s_layouts(alignment): plm.add_type("fifo_space_request", ("channel", 16)) plm.add_type("read_request", ("channel", 16), ("timeout", 64)) - plm.add_type("read_consume") # channel is specified in the last read_request packet return plm diff --git a/artiq/gateware/rtio/cri.py b/artiq/gateware/rtio/cri.py index 044605ef6..5c8918c76 100644 --- a/artiq/gateware/rtio/cri.py +++ b/artiq/gateware/rtio/cri.py @@ -42,7 +42,7 @@ layout = [ ("i_data", 32, DIR_S_TO_M), ("i_timestamp", 64, DIR_S_TO_M), # i_status bits: - # <0:wait for event> <1:overflow> <2:wait for status> + # <0:wait for event (command timeout)> <1:overflow> <2:wait for status> ("i_status", 3, DIR_S_TO_M), ("counter", 64, DIR_S_TO_M)