mirror of https://github.com/m-labs/artiq.git
drtio: input support (untested)
This commit is contained in:
parent
d1b9f9d737
commit
497c795d8c
|
@ -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 += [
|
||||
|
|
|
@ -9,16 +9,26 @@ 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):
|
||||
self.add_output(n, channel)
|
||||
self.add_input(n, channel)
|
||||
|
||||
def add_output(self, n, channel):
|
||||
rt_packet = self.rt_packet
|
||||
max_fine_ts_width = self.max_fine_ts_width
|
||||
|
||||
interface = channel.interface.o
|
||||
data_width = rtlink.get_data_width(interface)
|
||||
address_width = rtlink.get_address_width(interface)
|
||||
|
@ -31,7 +41,7 @@ class IOS(Module):
|
|||
ev_layout.append(("data", data_width))
|
||||
if address_width:
|
||||
ev_layout.append(("address", address_width))
|
||||
ev_layout.append(("timestamp", len(tsc) + fine_ts_width))
|
||||
ev_layout.append(("timestamp", len(self.tsc) + fine_ts_width))
|
||||
|
||||
fifo = ClockDomainsRenamer("rio")(
|
||||
SyncFIFOBuffered(layout_len(ev_layout), channel.ofifo_depth))
|
||||
|
@ -59,7 +69,7 @@ class IOS(Module):
|
|||
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),
|
||||
If(rt_packet.write_timestamp[max_fine_ts_width:] < (self.tsc + 4),
|
||||
rt_packet.write_underflow.eq(1)
|
||||
)
|
||||
)
|
||||
|
@ -76,7 +86,7 @@ class IOS(Module):
|
|||
fifo.re.eq(0),
|
||||
interface.stb.eq(0),
|
||||
If(fifo.readable &
|
||||
(fifo_out.timestamp[fine_ts_width:] == tsc),
|
||||
(fifo_out.timestamp[fine_ts_width:] == self.tsc),
|
||||
fifo.re.eq(1),
|
||||
interface.stb.eq(1)
|
||||
)
|
||||
|
@ -87,3 +97,60 @@ class IOS(Module):
|
|||
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:
|
||||
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)
|
||||
)
|
||||
]
|
||||
|
|
|
@ -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 <channel>
|
||||
# notwrite=1 address=1 read request <channel, timestamp>
|
||||
# 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()
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue