gateware: common RTIO interface

This commit is contained in:
Sebastien Bourdeauducq 2016-11-22 22:46:50 +08:00
parent 0aaf120ca7
commit 9acc7d135e
12 changed files with 203 additions and 142 deletions

View File

@ -57,13 +57,11 @@ class DRTIOMaster(Module):
self.submodules.rt_controller = rt_controller.RTController(
self.rt_packets, channel_count, fine_ts_width)
self.submodules.rt_manager = rt_controller.RTManager(self.rt_packets)
self.cri = self.rt_controller.cri
self.submodules.aux_controller = aux_controller.AuxController(
self.link_layer)
def get_kernel_csrs(self):
return self.rt_controller.get_kernel_csrs()
def get_csrs(self):
return (self.link_layer.get_csrs() +
self.rt_controller.get_csrs() +

View File

@ -5,7 +5,7 @@ from migen.genlib.misc import WaitTimer
from misoc.interconnect.csr import *
from artiq.gateware.rtio.cdc import RTIOCounter
from artiq.gateware.rtio.kernel_csrs import KernelCSRs
from artiq.gateware.rtio import cri
class _CSRs(AutoCSR):
@ -27,20 +27,20 @@ class _CSRs(AutoCSR):
class RTController(Module):
def __init__(self, rt_packets, channel_count, fine_ts_width):
self.kcsrs = KernelCSRs()
self.csrs = _CSRs()
self.cri = cri.Interface()
self.comb += self.cri.arb_gnt.eq(1)
# channel selection
chan_sel = Signal(16)
self.comb += chan_sel.eq(
Mux(self.csrs.chan_sel_override_en.storage,
self.csrs.chan_sel_override.storage,
self.kcsrs.chan_sel.storage))
self.cri.chan_sel[:16]))
# master RTIO counter and counter synchronization
self.submodules.counter = RTIOCounter(64-fine_ts_width)
self.sync += If(self.kcsrs.counter_update.re,
self.kcsrs.counter.status.eq(self.counter.value_sys << fine_ts_width))
self.comb += self.cri.counter.eq(self.counter.value_sys << fine_ts_width)
tsc_correction = Signal(64)
self.csrs.tsc_correction.storage.attr.add("no_retiming")
self.specials += MultiReg(self.csrs.tsc_correction.storage, tsc_correction)
@ -67,14 +67,14 @@ class RTController(Module):
self.comb += [
fifo_spaces.adr.eq(chan_sel),
last_timestamps.adr.eq(chan_sel),
last_timestamps.dat_w.eq(self.kcsrs.o_timestamp.storage),
last_timestamps.dat_w.eq(self.cri.o_timestamp),
rt_packets.write_channel.eq(chan_sel),
rt_packets.write_address.eq(self.kcsrs.o_address.storage),
rt_packets.write_data.eq(self.kcsrs.o_data.storage),
rt_packets.write_address.eq(self.cri.o_address),
rt_packets.write_data.eq(self.cri.o_data),
If(rt_packets_fifo_request,
rt_packets.write_timestamp.eq(0xffff000000000000)
).Else(
rt_packets.write_timestamp.eq(self.kcsrs.o_timestamp.storage)
rt_packets.write_timestamp.eq(self.cri.o_timestamp)
)
]
@ -85,15 +85,15 @@ class RTController(Module):
status_underflow = Signal()
status_sequence_error = Signal()
self.comb += [
self.kcsrs.o_status.status.eq(Cat(
self.cri.o_status.eq(Cat(
status_wait, status_underflow, status_sequence_error)),
self.csrs.o_wait.status.eq(status_wait)
]
sequence_error_set = Signal()
underflow_set = Signal()
self.sync += [
If(self.kcsrs.o_underflow_reset.re, status_underflow.eq(0)),
If(self.kcsrs.o_sequence_error_reset.re, status_sequence_error.eq(0)),
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)),
]
@ -107,14 +107,14 @@ class RTController(Module):
self.submodules += timeout_counter
# TODO: collision, replace, busy
cond_sequence_error = self.kcsrs.o_timestamp.storage < last_timestamps.dat_r
cond_underflow = ((self.kcsrs.o_timestamp.storage[fine_ts_width:]
cond_sequence_error = self.cri.o_timestamp < last_timestamps.dat_r
cond_underflow = ((self.cri.o_timestamp[fine_ts_width:]
- self.csrs.underflow_margin.storage[fine_ts_width:]) < self.counter.value_sys)
cond_fifo_emptied = ((last_timestamps.dat_r[fine_ts_width:] < self.counter.value_sys)
& (last_timestamps.dat_r != 0))
fsm.act("IDLE",
If(self.kcsrs.o_we.re,
If(self.cri.cmd == cri.commands["write"],
If(cond_sequence_error,
sequence_error_set.eq(1)
).Elif(cond_underflow,
@ -184,9 +184,6 @@ class RTController(Module):
)
]
def get_kernel_csrs(self):
return self.kcsrs.get_csrs()
def get_csrs(self):
return self.csrs.get_csrs()

View File

@ -1,3 +1,4 @@
from artiq.gateware.rtio.core import Channel, LogChannel, RTIO
from artiq.gateware.rtio.cri import KernelInitiator
from artiq.gateware.rtio.core import Channel, LogChannel, Core
from artiq.gateware.rtio.analyzer import Analyzer
from artiq.gateware.rtio.moninj import MonInj

View File

@ -42,7 +42,7 @@ assert layout_len(stopped_layout) == message_len
class MessageEncoder(Module, AutoCSR):
def __init__(self, rtio_core, enable):
def __init__(self, kcsrs, rtio_counter, enable):
self.source = stream.Endpoint([("data", message_len)])
self.overflow = CSRStatus()
@ -50,27 +50,15 @@ class MessageEncoder(Module, AutoCSR):
# # #
kcsrs = rtio_core.kcsrs
input_output_stb = Signal()
input_output = Record(input_output_layout)
if hasattr(kcsrs, "o_data"):
o_data = kcsrs.o_data.storage
else:
o_data = 0
if hasattr(kcsrs, "o_address"):
o_address = kcsrs.o_address.storage
else:
o_address = 0
if hasattr(kcsrs, "i_data"):
i_data = kcsrs.i_data.status
else:
i_data = 0
o_data = kcsrs.o_data.storage
o_address = kcsrs.o_address.storage
i_data = kcsrs.i_data.status
self.comb += [
input_output.channel.eq(kcsrs.chan_sel.storage),
input_output.address_padding.eq(o_address),
input_output.rtio_counter.eq(
rtio_core.counter.value_sys << rtio_core.fine_ts_width),
input_output.rtio_counter.eq(rtio_counter),
If(kcsrs.o_we.re,
input_output.message_type.eq(MessageType.output.value),
input_output.timestamp.eq(kcsrs.o_timestamp.storage),
@ -88,10 +76,10 @@ class MessageEncoder(Module, AutoCSR):
self.comb += [
exception.message_type.eq(MessageType.exception.value),
exception.channel.eq(kcsrs.chan_sel.storage),
exception.rtio_counter.eq(
rtio_core.counter.value_sys << rtio_core.fine_ts_width),
exception.rtio_counter.eq(rtio_counter),
]
for ename in ("o_underflow_reset", "o_sequence_error_reset",
for ename in ("reset", "reset_phy",
"o_underflow_reset", "o_sequence_error_reset",
"o_collision_reset", "i_overflow_reset"):
self.comb += \
If(getattr(kcsrs, ename).re,
@ -99,28 +87,11 @@ class MessageEncoder(Module, AutoCSR):
exception.exception_type.eq(
getattr(ExceptionType, ename).value)
)
for rname in "reset", "reset_phy":
r_d = Signal(reset=1)
r = getattr(kcsrs, rname).storage
self.sync += r_d.eq(r)
self.comb += [
If(r & ~r_d,
exception_stb.eq(1),
exception.exception_type.eq(
getattr(ExceptionType, rname+"_rising").value)
),
If(~r & r_d,
exception_stb.eq(1),
exception.exception_type.eq(
getattr(ExceptionType, rname+"_falling").value)
)
]
stopped = Record(stopped_layout)
self.comb += [
stopped.message_type.eq(MessageType.stopped.value),
stopped.rtio_counter.eq(
rtio_core.counter.value_sys << rtio_core.fine_ts_width),
stopped.rtio_counter.eq(rtio_counter),
]
enable_r = Signal()
@ -210,13 +181,13 @@ class DMAWriter(Module, AutoCSR):
class Analyzer(Module, AutoCSR):
def __init__(self, rtio_core, membus, fifo_depth=128):
def __init__(self, kcsrs, rtio_counter, membus, fifo_depth=128):
# shutdown procedure: set enable to 0, wait until busy=0
self.enable = CSRStorage()
self.busy = CSRStatus()
self.submodules.message_encoder = MessageEncoder(
rtio_core, self.enable.storage)
kcsrs, rtio_counter, self.enable.storage)
self.submodules.fifo = stream.SyncFIFO(
[("data", message_len)], fifo_depth, True)
self.submodules.converter = stream.Converter(

View File

@ -6,8 +6,7 @@ from migen.genlib.record import Record
from migen.genlib.fifo import AsyncFIFO
from migen.genlib.resetsync import AsyncResetSynchronizer
from artiq.gateware.rtio import rtlink
from artiq.gateware.rtio.kernel_csrs import KernelCSRs
from artiq.gateware.rtio import cri, rtlink
from artiq.gateware.rtio.cdc import *
@ -265,7 +264,7 @@ class LogChannel:
self.overrides = []
class RTIO(Module):
class Core(Module):
def __init__(self, channels, full_ts_width=63, guard_io_cycles=20):
data_width = max(rtlink.get_data_width(c.interface)
for c in channels)
@ -278,35 +277,43 @@ class RTIO(Module):
self.address_width = address_width
self.fine_ts_width = fine_ts_width
self.kcsrs = KernelCSRs()
self.cri = cri.Interface()
self.comb += self.cri.arb_gnt.eq(1)
# Clocking/Reset
# Create rsys, rio and rio_phy domains based on sys and rtio
# with reset controlled by CSR.
# with reset controlled by CRI.
cmd_reset = Signal(reset=1)
cmd_reset_phy = Signal(reset=1)
self.sync += [
cmd_reset.eq(self.cri.cmd == cri.commands["reset"]),
cmd_reset_phy.eq(self.cri.cmd == cri.commands["reset_phy"])
]
cmd_reset.attr.add("no_retiming")
cmd_reset_phy.attr.add("no_retiming")
self.clock_domains.cd_rsys = ClockDomain()
self.clock_domains.cd_rio = ClockDomain()
self.clock_domains.cd_rio_phy = ClockDomain()
self.comb += [
self.cd_rsys.clk.eq(ClockSignal()),
self.cd_rsys.rst.eq(self.kcsrs.reset.storage)
self.cd_rsys.rst.eq(cmd_reset)
]
self.comb += self.cd_rio.clk.eq(ClockSignal("rtio"))
self.specials += AsyncResetSynchronizer(
self.cd_rio,
self.kcsrs.reset.storage | ResetSignal("rtio",
allow_reset_less=True))
cmd_reset | ResetSignal("rtio", allow_reset_less=True))
self.comb += self.cd_rio_phy.clk.eq(ClockSignal("rtio"))
self.specials += AsyncResetSynchronizer(
self.cd_rio_phy,
self.kcsrs.reset_phy.storage | ResetSignal("rtio",
allow_reset_less=True))
cmd_reset_phy | ResetSignal("rtio", allow_reset_less=True))
# Managers
self.submodules.counter = RTIOCounter(full_ts_width - fine_ts_width)
i_datas, i_timestamps = [], []
o_statuses, i_statuses = [], []
sel = self.kcsrs.chan_sel.storage
sel = self.cri.chan_sel[:16]
for n, channel in enumerate(channels):
if isinstance(channel, LogChannel):
i_datas.append(0)
@ -322,30 +329,27 @@ class RTIO(Module):
self.submodules += o_manager
if hasattr(o_manager.ev, "data"):
self.comb += o_manager.ev.data.eq(
self.kcsrs.o_data.storage)
self.comb += o_manager.ev.data.eq(self.cri.o_data)
if hasattr(o_manager.ev, "address"):
self.comb += o_manager.ev.address.eq(
self.kcsrs.o_address.storage)
ts_shift = (len(self.kcsrs.o_timestamp.storage)
- len(o_manager.ev.timestamp))
self.comb += o_manager.ev.timestamp.eq(
self.kcsrs.o_timestamp.storage[ts_shift:])
self.comb += o_manager.ev.address.eq(self.cri.o_address)
ts_shift = len(self.cri.o_timestamp) - len(o_manager.ev.timestamp)
self.comb += o_manager.ev.timestamp.eq(self.cri.o_timestamp[ts_shift:])
self.comb += o_manager.we.eq(selected & self.kcsrs.o_we.re)
self.comb += o_manager.we.eq(selected &
(self.cri.cmd == cri.commands["write"]))
underflow = Signal()
sequence_error = Signal()
collision = Signal()
busy = Signal()
self.sync.rsys += [
If(selected & self.kcsrs.o_underflow_reset.re,
If(selected & (self.cri.cmd == cri.commands["o_underflow_reset"]),
underflow.eq(0)),
If(selected & self.kcsrs.o_sequence_error_reset.re,
If(selected & (self.cri.cmd == cri.commands["o_sequence_error_reset"]),
sequence_error.eq(0)),
If(selected & self.kcsrs.o_collision_reset.re,
If(selected & (self.cri.cmd == cri.commands["o_collision_reset"]),
collision.eq(0)),
If(selected & self.kcsrs.o_busy_reset.re,
If(selected & (self.cri.cmd == cri.commands["o_busy_reset"]),
busy.eq(0)),
If(o_manager.underflow, underflow.eq(1)),
If(o_manager.sequence_error, sequence_error.eq(1)),
@ -368,17 +372,17 @@ class RTIO(Module):
else:
i_datas.append(0)
if channel.interface.i.timestamped:
ts_shift = (len(self.kcsrs.i_timestamp.status)
ts_shift = (len(self.cri.i_timestamp)
- len(i_manager.ev.timestamp))
i_timestamps.append(i_manager.ev.timestamp << ts_shift)
else:
i_timestamps.append(0)
self.comb += i_manager.re.eq(selected & self.kcsrs.i_re.re)
self.comb += i_manager.re.eq(selected & (self.cri.cmd == cri.commands["read"]))
overflow = Signal()
self.sync.rsys += [
If(selected & self.kcsrs.i_overflow_reset.re,
If(selected & (self.cri.cmd == cri.commands["i_overflow_reset"]),
overflow.eq(0)),
If(i_manager.overflow,
overflow.eq(1))
@ -389,20 +393,11 @@ class RTIO(Module):
i_datas.append(0)
i_timestamps.append(0)
i_statuses.append(0)
if data_width:
self.comb += self.kcsrs.i_data.status.eq(Array(i_datas)[sel])
self.comb += [
self.kcsrs.i_timestamp.status.eq(Array(i_timestamps)[sel]),
self.kcsrs.o_status.status.eq(Array(o_statuses)[sel]),
self.kcsrs.i_status.status.eq(Array(i_statuses)[sel])
self.cri.i_data.eq(Array(i_datas)[sel]),
self.cri.i_timestamp.eq(Array(i_timestamps)[sel]),
self.cri.o_status.eq(Array(o_statuses)[sel]),
self.cri.i_status.eq(Array(i_statuses)[sel])
]
# Counter access
self.sync += \
If(self.kcsrs.counter_update.re,
self.kcsrs.counter.status.eq(self.counter.value_sys
<< fine_ts_width)
)
def get_csrs(self):
return self.kcsrs.get_csrs()
self.cri.counter.eq(self.counter.value_sys << fine_ts_width)

124
artiq/gateware/rtio/cri.py Normal file
View File

@ -0,0 +1,124 @@
"""Common RTIO Interface"""
from migen import *
from migen.genlib.record import *
from misoc.interconnect.csr import *
commands = {
"nop": 0,
"reset": 1,
"reset_phy": 2,
"write": 3,
"read": 4,
"o_underflow_reset": 5,
"o_sequence_error_reset": 6,
"o_collision_reset": 7,
"o_busy_reset": 8,
"i_overflow_reset": 9
}
layout = [
("arb_req", 1, DIR_M_TO_S),
("arb_gnt", 1, DIR_S_TO_M),
("cmd", 4, DIR_M_TO_S),
# 8 MSBs of chan_sel are used to select core
("chan_sel", 24, DIR_M_TO_S),
("o_data", 512, DIR_M_TO_S),
("o_address", 16, DIR_M_TO_S),
("o_timestamp", 64, DIR_M_TO_S),
# o_status bits:
# <0:wait> <1:underflow> <2:sequence_error> <3:collision> <4:busy>
("o_status", 5, DIR_S_TO_M),
("i_data", 32, DIR_S_TO_M),
("i_timestamp", 64, DIR_S_TO_M),
# i_status bits:
# <0:wait> <1:overflow>
("i_status", 2, DIR_S_TO_M),
("counter", 64, DIR_S_TO_M)
]
class Interface(Record):
def __init__(self):
Record.__init__(self, layout)
class KernelInitiator(Module, AutoCSR):
def __init__(self, cri=None):
self.arb_req = CSRStorage()
self.arb_gnt = CSRStatus()
self.reset = CSR()
self.reset_phy = CSR()
self.chan_sel = CSRStorage(24)
self.o_data = CSRStorage(32, write_from_dev=True) # XXX -> 512
self.o_address = CSRStorage(16)
self.o_timestamp = CSRStorage(64)
self.o_we = CSR()
self.o_status = CSRStatus(5)
self.o_underflow_reset = CSR()
self.o_sequence_error_reset = CSR()
self.o_collision_reset = CSR()
self.o_busy_reset = CSR()
self.i_data = CSRStatus(32)
self.i_timestamp = CSRStatus(64)
self.i_re = CSR()
self.i_status = CSRStatus(2)
self.i_overflow_reset = CSR()
self.counter = CSRStatus(64)
self.counter_update = CSR()
if cri is None:
cri = Interface()
self.cri = cri
# # #
self.comb += [
self.cri.arb_req.eq(self.arb_req.storage),
self.arb_gnt.status.eq(self.cri.arb_gnt),
self.cri.cmd.eq(commands["nop"]),
If(self.reset.re, self.cri.cmd.eq(commands["reset"])),
If(self.reset_phy.re, self.cri.cmd.eq(commands["reset_phy"])),
If(self.o_we.re, self.cri.cmd.eq(commands["write"])),
If(self.i_re.re, self.cri.cmd.eq(commands["read"])),
If(self.o_underflow_reset.re, self.cri.cmd.eq(commands["o_underflow_reset"])),
If(self.o_sequence_error_reset.re, self.cri.cmd.eq(commands["o_sequence_error_reset"])),
If(self.o_collision_reset.re, self.cri.cmd.eq(commands["o_collision_reset"])),
If(self.o_busy_reset.re, self.cri.cmd.eq(commands["o_busy_reset"])),
If(self.i_overflow_reset.re, self.cri.cmd.eq(commands["i_overflow_reset"])),
self.cri.chan_sel.eq(self.chan_sel.storage),
self.cri.o_data.eq(self.o_data.storage),
self.cri.o_address.eq(self.o_address.storage),
self.cri.o_timestamp.eq(self.o_timestamp.storage),
self.o_status.status.eq(self.cri.o_status),
self.i_data.status.eq(self.cri.i_data),
self.i_timestamp.status.eq(self.cri.i_timestamp),
self.i_status.status.eq(self.cri.i_status),
self.o_data.dat_w.eq(0),
self.o_data.we.eq(self.o_timestamp.re),
]
self.sync += If(self.counter_update.re, self.counter.status.eq(self.cri.counter))
def get_csrs(self):
return []
def get_kernel_csrs(self):
return AutoCSR.get_csrs(self)

View File

@ -1,27 +0,0 @@
from misoc.interconnect.csr import *
class KernelCSRs(AutoCSR):
def __init__(self):
self.reset = CSRStorage(reset=1)
self.reset_phy = CSRStorage(reset=1)
self.chan_sel = CSRStorage(16)
self.o_data = CSRStorage(32)
self.o_address = CSRStorage(16)
self.o_timestamp = CSRStorage(64)
self.o_we = CSR()
self.o_status = CSRStatus(5)
self.o_underflow_reset = CSR()
self.o_sequence_error_reset = CSR()
self.o_collision_reset = CSR()
self.o_busy_reset = CSR()
self.i_data = CSRStatus(32)
self.i_timestamp = CSRStatus(64)
self.i_re = CSR()
self.i_status = CSRStatus(2)
self.i_overflow_reset = CSR()
self.counter = CSRStatus(64)
self.counter_update = CSR()

View File

@ -142,7 +142,8 @@ class _NIST_Ions(MiniSoC, AMPSoC):
def add_rtio(self, rtio_channels):
self.submodules.rtio_crg = _RTIOCRG(self.platform, self.crg.cd_sys.clk)
self.csr_devices.append("rtio_crg")
self.submodules.rtio = rtio.RTIO(rtio_channels)
self.submodules.rtio_core = rtio.Core(rtio_channels)
self.submodules.rtio = rtio.KernelInitiator(self.rtio_core.cri)
self.register_kernel_cpu_csrdevice("rtio")
self.submodules.rtio_moninj = rtio.MonInj(rtio_channels)
self.csr_devices.append("rtio_moninj")
@ -153,8 +154,8 @@ class _NIST_Ions(MiniSoC, AMPSoC):
self.crg.cd_sys.clk,
self.rtio_crg.cd_rtio.clk)
self.submodules.rtio_analyzer = rtio.Analyzer(self.rtio,
self.get_native_sdram_if())
self.submodules.rtio_analyzer = rtio.Analyzer(
self.rtio, self.rtio_core.cri.counter, self.get_native_sdram_if())
self.csr_devices.append("rtio_analyzer")

View File

@ -8,6 +8,7 @@ from misoc.targets.kc705 import MiniSoC, soc_kc705_args, soc_kc705_argdict
from misoc.integration.builder import builder_args, builder_argdict
from artiq.gateware.soc import AMPSoC, build_artiq_soc
from artiq.gateware import rtio
from artiq.gateware.drtio.transceiver import gtx_7series
from artiq.gateware.drtio import DRTIOMaster
from artiq import __version__ as artiq_version
@ -41,7 +42,8 @@ class Master(MiniSoC, AMPSoC):
sys_clk_freq=self.clk_freq,
clock_div2=True)
self.submodules.drtio = DRTIOMaster(self.transceiver)
self.register_kernel_cpu_csrdevice("rtio", self.drtio.get_kernel_csrs())
self.submodules.rtio = rtio.KernelInitiator(self.drtio.cri)
self.register_kernel_cpu_csrdevice("rtio")
self.csr_devices.append("drtio")

View File

@ -216,12 +216,13 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd
rtio_channels.append(rtio.LogChannel())
# RTIO logic
self.submodules.rtio = rtio.RTIO(rtio_channels)
self.submodules.rtio_core = rtio.Core(rtio_channels)
self.submodules.rtio = rtio.KernelInitiator(self.rtio_core.cri)
self.register_kernel_cpu_csrdevice("rtio")
self.submodules.rtio_moninj = rtio.MonInj(rtio_channels)
self.csr_devices.append("rtio_moninj")
self.submodules.rtio_analyzer = rtio.Analyzer(
self.rtio, self.get_native_sdram_if())
self.rtio, self.rtio_core.cri.counter, self.get_native_sdram_if())
self.csr_devices.append("rtio_analyzer")

View File

@ -9,10 +9,10 @@ class MessageType(Enum):
class ExceptionType(Enum):
reset_rising = 0b000000
reset_falling = 0b000001
reset_phy_rising = 0b000010
reset_phy_falling = 0b000011
reset = 0b000000
legacy_reset_falling = 0b000001
reset_phy = 0b000010
legacy_reset_phy_falling = 0b000011
o_underflow_reset = 0b010000
o_sequence_error_reset = 0b010001

View File

@ -11,8 +11,6 @@ const RTIO_I_STATUS_OVERFLOW: u32 = 2;
pub extern fn init() {
unsafe {
csr::rtio::reset_write(1);
csr::rtio::reset_write(0);
csr::rtio::reset_phy_write(0);
}
}