drtio: input support (untested)

This commit is contained in:
Sebastien Bourdeauducq 2017-03-13 23:54:44 +08:00
parent d1b9f9d737
commit 497c795d8c
6 changed files with 265 additions and 102 deletions

View File

@ -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 += [

View File

@ -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)
)
]

View File

@ -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()

View File

@ -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",

View File

@ -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

View File

@ -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)