2016-10-24 19:50:13 +08:00
|
|
|
from migen import *
|
2016-10-31 00:53:01 +08:00
|
|
|
from migen.genlib.cdc import MultiReg
|
2016-11-18 17:44:48 +08:00
|
|
|
from migen.genlib.misc import WaitTimer
|
2016-12-12 18:48:10 +08:00
|
|
|
from migen.genlib.resetsync import AsyncResetSynchronizer
|
2016-10-24 19:50:13 +08:00
|
|
|
|
|
|
|
from misoc.interconnect.csr import *
|
|
|
|
|
|
|
|
from artiq.gateware.rtio.cdc import RTIOCounter
|
2016-11-22 22:46:50 +08:00
|
|
|
from artiq.gateware.rtio import cri
|
2016-10-24 19:50:13 +08:00
|
|
|
|
2016-10-31 18:09:36 +08:00
|
|
|
|
|
|
|
class _CSRs(AutoCSR):
|
|
|
|
def __init__(self):
|
|
|
|
self.chan_sel_override = CSRStorage(16)
|
|
|
|
self.chan_sel_override_en = CSRStorage()
|
|
|
|
|
2016-10-24 19:50:13 +08:00
|
|
|
self.tsc_correction = CSRStorage(64)
|
|
|
|
self.set_time = CSR()
|
2016-10-25 12:41:16 +08:00
|
|
|
self.underflow_margin = CSRStorage(16, reset=200)
|
2016-10-24 19:50:13 +08:00
|
|
|
|
2016-12-09 14:16:55 +08:00
|
|
|
self.reset = CSR()
|
|
|
|
self.reset_phy = CSR()
|
|
|
|
|
2016-10-25 12:41:16 +08:00
|
|
|
self.o_get_fifo_space = CSR()
|
|
|
|
self.o_dbg_fifo_space = CSRStatus(16)
|
|
|
|
self.o_dbg_last_timestamp = CSRStatus(64)
|
|
|
|
self.o_reset_channel_status = CSR()
|
2016-10-31 18:09:36 +08:00
|
|
|
self.o_wait = CSRStatus()
|
2016-11-18 17:44:48 +08:00
|
|
|
self.o_fifo_space_timeout = CSR()
|
2016-10-24 19:50:13 +08:00
|
|
|
|
|
|
|
|
|
|
|
class RTController(Module):
|
2016-10-25 12:41:16 +08:00
|
|
|
def __init__(self, rt_packets, channel_count, fine_ts_width):
|
2016-10-31 18:09:36 +08:00
|
|
|
self.csrs = _CSRs()
|
2016-11-22 22:46:50 +08:00
|
|
|
self.cri = cri.Interface()
|
|
|
|
self.comb += self.cri.arb_gnt.eq(1)
|
2016-10-31 18:09:36 +08:00
|
|
|
|
2016-11-04 19:38:24 +08:00
|
|
|
# channel selection
|
2016-10-31 18:09:36 +08:00
|
|
|
chan_sel = Signal(16)
|
|
|
|
self.comb += chan_sel.eq(
|
|
|
|
Mux(self.csrs.chan_sel_override_en.storage,
|
|
|
|
self.csrs.chan_sel_override.storage,
|
2016-11-22 22:46:50 +08:00
|
|
|
self.cri.chan_sel[:16]))
|
2016-10-24 19:50:13 +08:00
|
|
|
|
2016-11-04 19:38:24 +08:00
|
|
|
# master RTIO counter and counter synchronization
|
2016-10-26 11:48:47 +08:00
|
|
|
self.submodules.counter = RTIOCounter(64-fine_ts_width)
|
2016-11-22 22:46:50 +08:00
|
|
|
self.comb += self.cri.counter.eq(self.counter.value_sys << fine_ts_width)
|
2016-10-24 19:50:13 +08:00
|
|
|
tsc_correction = Signal(64)
|
2016-10-31 18:09:36 +08:00
|
|
|
self.csrs.tsc_correction.storage.attr.add("no_retiming")
|
|
|
|
self.specials += MultiReg(self.csrs.tsc_correction.storage, tsc_correction)
|
2016-10-24 19:50:13 +08:00
|
|
|
self.comb += [
|
|
|
|
rt_packets.tsc_value.eq(
|
|
|
|
self.counter.value_rtio + tsc_correction),
|
2016-10-31 18:09:36 +08:00
|
|
|
self.csrs.set_time.w.eq(rt_packets.set_time_stb)
|
2016-10-24 19:50:13 +08:00
|
|
|
]
|
|
|
|
self.sync += [
|
|
|
|
If(rt_packets.set_time_ack, rt_packets.set_time_stb.eq(0)),
|
2016-10-31 18:09:36 +08:00
|
|
|
If(self.csrs.set_time.re, rt_packets.set_time_stb.eq(1))
|
2016-10-24 19:50:13 +08:00
|
|
|
]
|
|
|
|
|
2016-12-12 17:49:07 +08:00
|
|
|
# reset
|
|
|
|
self.sync += [
|
|
|
|
If(rt_packets.reset_ack, rt_packets.reset_stb.eq(0)),
|
|
|
|
If(self.csrs.reset.re,
|
|
|
|
rt_packets.reset_stb.eq(1),
|
|
|
|
rt_packets.reset_phy.eq(0)
|
|
|
|
),
|
|
|
|
If(self.csrs.reset_phy.re,
|
|
|
|
rt_packets.reset_stb.eq(1),
|
|
|
|
rt_packets.reset_phy.eq(1)
|
|
|
|
),
|
|
|
|
]
|
|
|
|
|
2016-12-12 18:48:10 +08:00
|
|
|
local_reset = Signal(reset=1)
|
|
|
|
self.sync += local_reset.eq(self.csrs.reset.re)
|
|
|
|
local_reset.attr.add("no_retiming")
|
2016-12-13 14:19:49 +08:00
|
|
|
self.clock_domains.cd_sys_with_rst = ClockDomain()
|
|
|
|
self.clock_domains.cd_rtio_with_rst = ClockDomain()
|
2016-12-12 18:48:10 +08:00
|
|
|
self.comb += [
|
2016-12-13 14:19:49 +08:00
|
|
|
self.cd_sys_with_rst.clk.eq(ClockSignal()),
|
|
|
|
self.cd_sys_with_rst.rst.eq(local_reset)
|
2016-12-12 18:48:10 +08:00
|
|
|
]
|
2016-12-13 14:19:49 +08:00
|
|
|
self.comb += self.cd_rtio_with_rst.clk.eq(ClockSignal("rtio"))
|
|
|
|
self.specials += AsyncResetSynchronizer(self.cd_rtio_with_rst, local_reset)
|
2016-12-12 18:48:10 +08:00
|
|
|
|
2016-11-04 19:38:24 +08:00
|
|
|
# remote channel status cache
|
2016-10-24 19:50:13 +08:00
|
|
|
fifo_spaces_mem = Memory(16, channel_count)
|
|
|
|
fifo_spaces = fifo_spaces_mem.get_port(write_capable=True)
|
|
|
|
self.specials += fifo_spaces_mem, fifo_spaces
|
|
|
|
last_timestamps_mem = Memory(64, channel_count)
|
|
|
|
last_timestamps = last_timestamps_mem.get_port(write_capable=True)
|
|
|
|
self.specials += last_timestamps_mem, last_timestamps
|
|
|
|
|
2016-11-04 19:38:24 +08:00
|
|
|
# common packet fields
|
2016-10-24 19:50:13 +08:00
|
|
|
rt_packets_fifo_request = Signal()
|
|
|
|
self.comb += [
|
2016-10-31 18:09:36 +08:00
|
|
|
fifo_spaces.adr.eq(chan_sel),
|
|
|
|
last_timestamps.adr.eq(chan_sel),
|
2016-11-22 22:46:50 +08:00
|
|
|
last_timestamps.dat_w.eq(self.cri.o_timestamp),
|
2016-10-31 18:09:36 +08:00
|
|
|
rt_packets.write_channel.eq(chan_sel),
|
2016-11-22 22:46:50 +08:00
|
|
|
rt_packets.write_address.eq(self.cri.o_address),
|
|
|
|
rt_packets.write_data.eq(self.cri.o_data),
|
2016-10-24 19:50:13 +08:00
|
|
|
If(rt_packets_fifo_request,
|
|
|
|
rt_packets.write_timestamp.eq(0xffff000000000000)
|
|
|
|
).Else(
|
2016-11-22 22:46:50 +08:00
|
|
|
rt_packets.write_timestamp.eq(self.cri.o_timestamp)
|
2016-10-24 19:50:13 +08:00
|
|
|
)
|
|
|
|
]
|
|
|
|
|
2016-12-13 14:19:49 +08:00
|
|
|
fsm = ClockDomainsRenamer("sys_with_rst")(FSM())
|
2016-10-24 19:50:13 +08:00
|
|
|
self.submodules += fsm
|
|
|
|
|
|
|
|
status_wait = Signal()
|
|
|
|
status_underflow = Signal()
|
|
|
|
status_sequence_error = Signal()
|
2016-10-31 18:09:36 +08:00
|
|
|
self.comb += [
|
2016-11-22 22:46:50 +08:00
|
|
|
self.cri.o_status.eq(Cat(
|
2016-10-31 18:09:36 +08:00
|
|
|
status_wait, status_underflow, status_sequence_error)),
|
|
|
|
self.csrs.o_wait.status.eq(status_wait)
|
|
|
|
]
|
2016-10-24 20:46:55 +08:00
|
|
|
sequence_error_set = Signal()
|
|
|
|
underflow_set = Signal()
|
2016-12-13 14:19:49 +08:00
|
|
|
self.sync.sys_with_rst += [
|
2016-11-22 22:46:50 +08:00
|
|
|
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)),
|
2016-10-24 20:46:55 +08:00
|
|
|
If(underflow_set, status_underflow.eq(1)),
|
2016-12-12 18:48:10 +08:00
|
|
|
If(sequence_error_set, status_sequence_error.eq(1))
|
2016-10-24 20:46:55 +08:00
|
|
|
]
|
2016-10-24 19:50:13 +08:00
|
|
|
|
2016-11-18 17:44:48 +08:00
|
|
|
signal_fifo_space_timeout = Signal()
|
2016-12-13 14:19:49 +08:00
|
|
|
self.sync.sys_with_rst += [
|
2016-11-18 17:44:48 +08:00
|
|
|
If(self.csrs.o_fifo_space_timeout.re, self.csrs.o_fifo_space_timeout.w.eq(0)),
|
|
|
|
If(signal_fifo_space_timeout, self.csrs.o_fifo_space_timeout.w.eq(1))
|
|
|
|
]
|
|
|
|
timeout_counter = WaitTimer(8191)
|
|
|
|
self.submodules += timeout_counter
|
|
|
|
|
2016-10-24 19:50:13 +08:00
|
|
|
# TODO: collision, replace, busy
|
2016-11-22 22:46:50 +08:00
|
|
|
cond_sequence_error = self.cri.o_timestamp < last_timestamps.dat_r
|
|
|
|
cond_underflow = ((self.cri.o_timestamp[fine_ts_width:]
|
2016-10-31 18:09:36 +08:00
|
|
|
- self.csrs.underflow_margin.storage[fine_ts_width:]) < self.counter.value_sys)
|
2016-10-24 19:50:13 +08:00
|
|
|
|
|
|
|
fsm.act("IDLE",
|
2016-11-22 22:46:50 +08:00
|
|
|
If(self.cri.cmd == cri.commands["write"],
|
2016-10-24 19:50:13 +08:00
|
|
|
If(cond_sequence_error,
|
|
|
|
sequence_error_set.eq(1)
|
|
|
|
).Elif(cond_underflow,
|
|
|
|
underflow_set.eq(1)
|
|
|
|
).Else(
|
|
|
|
NextState("WRITE")
|
|
|
|
)
|
|
|
|
),
|
2016-10-31 18:09:36 +08:00
|
|
|
If(self.csrs.o_get_fifo_space.re,
|
2016-10-24 19:50:13 +08:00
|
|
|
NextState("GET_FIFO_SPACE")
|
|
|
|
)
|
|
|
|
)
|
|
|
|
fsm.act("WRITE",
|
|
|
|
status_wait.eq(1),
|
|
|
|
rt_packets.write_stb.eq(1),
|
|
|
|
If(rt_packets.write_ack,
|
|
|
|
fifo_spaces.we.eq(1),
|
2017-01-11 04:31:03 +08:00
|
|
|
fifo_spaces.dat_w.eq(fifo_spaces.dat_r - 1),
|
2016-10-24 19:50:13 +08:00
|
|
|
last_timestamps.we.eq(1),
|
2017-01-11 04:31:03 +08:00
|
|
|
If(fifo_spaces.dat_r <= 1,
|
2016-10-24 19:50:13 +08:00
|
|
|
NextState("GET_FIFO_SPACE")
|
|
|
|
).Else(
|
|
|
|
NextState("IDLE")
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
fsm.act("GET_FIFO_SPACE",
|
|
|
|
status_wait.eq(1),
|
|
|
|
rt_packets_fifo_request.eq(1),
|
|
|
|
rt_packets.write_stb.eq(1),
|
2016-12-12 18:02:56 +08:00
|
|
|
rt_packets.fifo_space_not_ack.eq(1),
|
2016-10-24 19:50:13 +08:00
|
|
|
If(rt_packets.write_ack,
|
|
|
|
NextState("GET_FIFO_SPACE_REPLY")
|
|
|
|
)
|
|
|
|
)
|
|
|
|
fsm.act("GET_FIFO_SPACE_REPLY",
|
|
|
|
status_wait.eq(1),
|
|
|
|
fifo_spaces.dat_w.eq(rt_packets.fifo_space),
|
|
|
|
fifo_spaces.we.eq(1),
|
2016-10-24 23:10:15 +08:00
|
|
|
rt_packets.fifo_space_not_ack.eq(1),
|
2016-10-24 19:50:13 +08:00
|
|
|
If(rt_packets.fifo_space_not,
|
2017-01-11 04:31:03 +08:00
|
|
|
If(rt_packets.fifo_space != 0,
|
2016-10-24 19:50:13 +08:00
|
|
|
NextState("IDLE")
|
|
|
|
).Else(
|
|
|
|
NextState("GET_FIFO_SPACE")
|
|
|
|
)
|
2016-11-18 17:44:48 +08:00
|
|
|
),
|
|
|
|
timeout_counter.wait.eq(1),
|
|
|
|
If(timeout_counter.done,
|
|
|
|
signal_fifo_space_timeout.eq(1),
|
2017-01-11 06:12:32 +08:00
|
|
|
NextState("GET_FIFO_SPACE")
|
2016-10-24 19:50:13 +08:00
|
|
|
)
|
|
|
|
)
|
|
|
|
|
2016-11-04 17:53:42 +08:00
|
|
|
# channel state access
|
2016-10-24 19:50:13 +08:00
|
|
|
self.comb += [
|
2016-10-31 18:09:36 +08:00
|
|
|
self.csrs.o_dbg_fifo_space.status.eq(fifo_spaces.dat_r),
|
|
|
|
self.csrs.o_dbg_last_timestamp.status.eq(last_timestamps.dat_r),
|
|
|
|
If(self.csrs.o_reset_channel_status.re,
|
2016-10-24 19:50:13 +08:00
|
|
|
fifo_spaces.dat_w.eq(0),
|
|
|
|
fifo_spaces.we.eq(1),
|
|
|
|
last_timestamps.dat_w.eq(0),
|
|
|
|
last_timestamps.we.eq(1)
|
|
|
|
)
|
|
|
|
]
|
|
|
|
|
2016-10-31 18:09:36 +08:00
|
|
|
def get_csrs(self):
|
|
|
|
return self.csrs.get_csrs()
|
2016-11-04 19:38:24 +08:00
|
|
|
|
|
|
|
|
|
|
|
class RTManager(Module, AutoCSR):
|
|
|
|
def __init__(self, rt_packets):
|
|
|
|
self.request_echo = CSR()
|
|
|
|
|
2016-11-18 17:44:48 +08:00
|
|
|
self.packet_err_present = CSR()
|
|
|
|
self.packet_err_code = CSRStatus(8)
|
2016-11-04 19:38:24 +08:00
|
|
|
|
|
|
|
self.update_packet_cnt = CSR()
|
|
|
|
self.packet_cnt_tx = CSRStatus(32)
|
|
|
|
self.packet_cnt_rx = CSRStatus(32)
|
|
|
|
|
|
|
|
# # #
|
|
|
|
|
|
|
|
self.comb += self.request_echo.w.eq(rt_packets.echo_stb)
|
|
|
|
self.sync += [
|
|
|
|
If(rt_packets.echo_ack, rt_packets.echo_stb.eq(0)),
|
|
|
|
If(self.request_echo.re, rt_packets.echo_stb.eq(1))
|
|
|
|
]
|
|
|
|
|
|
|
|
self.comb += [
|
2016-11-18 17:44:48 +08:00
|
|
|
self.packet_err_present.w.eq(rt_packets.error_not),
|
|
|
|
rt_packets.error_not_ack.eq(self.packet_err_present.re),
|
|
|
|
self.packet_err_code.status.eq(rt_packets.error_code)
|
2016-11-04 19:38:24 +08:00
|
|
|
]
|
|
|
|
|
|
|
|
self.sync += \
|
|
|
|
If(self.update_packet_cnt.re,
|
|
|
|
self.packet_cnt_tx.status.eq(rt_packets.packet_cnt_tx),
|
|
|
|
self.packet_cnt_rx.status.eq(rt_packets.packet_cnt_rx)
|
|
|
|
)
|