mirror of
https://github.com/enjoy-digital/usb3_pipe.git
synced 2025-01-04 10:18:41 +08:00
176 lines
7.3 KiB
Python
176 lines
7.3 KiB
Python
# This file is Copyright (c) 2017-2019 Florent Kermarrec <florent@enjoy-digital.fr>
|
|
# License: BSD
|
|
|
|
import os
|
|
|
|
from migen import *
|
|
from migen.genlib.misc import WaitTimer
|
|
|
|
from litex.soc.interconnect.csr import *
|
|
from litex.soc.interconnect import stream
|
|
|
|
from usb3_pipe.serdes import RXWordAligner
|
|
|
|
# USB3 Core Endpoint --------------------------------------------------------------------------------
|
|
|
|
class USB3CoreEndpoint(Module, AutoCSR):
|
|
def __init__(self):
|
|
# Not functional but prevents synthesis optimizations
|
|
self._buf_in_addr = CSRStorage(9)
|
|
self._buf_in_data = CSRStorage(32)
|
|
self._buf_in_wren = CSR()
|
|
self._buf_in_request = CSRStatus()
|
|
self._buf_in_ready = CSRStatus()
|
|
self._buf_in_commit = CSR()
|
|
self._buf_in_commit_len = CSRStorage(11)
|
|
self._buf_in_commit_ack = CSRStatus()
|
|
self._buf_out_addr = CSRStorage(9)
|
|
self._buf_out_q = CSRStatus(32)
|
|
self._buf_out_len = CSRStatus(11)
|
|
self._buf_out_hasdata = CSRStatus()
|
|
self._buf_out_arm = CSR()
|
|
self._buf_out_arm_ack = CSRStatus()
|
|
|
|
# # #
|
|
|
|
self.buf_in_addr = self._buf_in_addr.storage
|
|
self.buf_in_data = self._buf_in_data.storage
|
|
self.buf_in_wren = self._buf_in_wren.re & self._buf_in_wren.r
|
|
self.buf_in_request = self._buf_in_request.status
|
|
self.buf_in_ready = self._buf_in_ready.status
|
|
self.buf_in_commit = self._buf_in_commit.re & self._buf_in_commit.r
|
|
self.buf_in_commit_len = self._buf_in_commit_len.storage
|
|
self.buf_in_commit_ack = self._buf_in_commit_ack.status
|
|
self.buf_out_addr = self._buf_out_addr.storage
|
|
self.buf_out_q = self._buf_out_q.status
|
|
self.buf_out_len = self._buf_out_len.status
|
|
self.buf_out_hasdata = self._buf_out_hasdata.status
|
|
self.buf_out_arm = self._buf_out_arm.re & self._buf_out_arm.r
|
|
self.buf_out_arm_ack = self._buf_out_arm_ack.status
|
|
|
|
# USB3 Core ----------------------------------------------------------------------------------------
|
|
|
|
class USB3Core(Module, AutoCSR):
|
|
def __init__(self, platform, with_endpoint=False):
|
|
self.reset = Signal()
|
|
self.sink = sink = stream.Endpoint([("data", 32), ("ctrl", 4)])
|
|
self.source = source = stream.Endpoint([("data", 32), ("ctrl", 4)])
|
|
# # #
|
|
|
|
# Artificial after reset delay from LT_POLLING_IDLE to LT_POLLING_U0
|
|
u0_timer = WaitTimer(32)
|
|
u0_timer = ResetInserter()(u0_timer)
|
|
self.submodules += u0_timer
|
|
self.comb += u0_timer.wait.eq(1)
|
|
self.comb += u0_timer.reset.eq(self.reset)
|
|
|
|
LT_POLLING_IDLE = 15
|
|
LT_POLLING_U0 = 16
|
|
ltssm_state = Signal(5)
|
|
self.comb += [
|
|
If(~u0_timer.done,
|
|
ltssm_state.eq(LT_POLLING_IDLE)
|
|
).Else(
|
|
ltssm_state.eq(LT_POLLING_U0)
|
|
)
|
|
]
|
|
|
|
# RX (Sink) --------------------------------------------------------------------------------
|
|
aligner = RXWordAligner(check_ctrl_only=True) # FIXME: can we avoid alignment here?
|
|
self.submodules.aligner = aligner
|
|
self.comb += sink.connect(aligner.sink)
|
|
|
|
in_data = Signal(32)
|
|
in_datak = Signal(4)
|
|
in_active = Signal()
|
|
self.comb += [
|
|
aligner.source.ready.eq(1), # Always ready
|
|
in_data.eq(aligner.source.data),
|
|
in_datak.eq(aligner.source.ctrl),
|
|
in_active.eq(aligner.source.valid),
|
|
]
|
|
|
|
# TX (Source) ------------------------------------------------------------------------------
|
|
# Daisho core does not support back-pressure (ready signal of LiteX's streams). To accomodate
|
|
# that, we use a FIFO that absorbs the data bursts from the core and re-transmits datas to
|
|
# the USB3 Pipe at the maximum allowed rate with back-pressure. This is a hack for our tests
|
|
# and should be fixed correctly in the core.
|
|
|
|
# FIFO
|
|
out_fifo = stream.SyncFIFO([("data", 32), ("ctrl", 4)], 128)
|
|
self.submodules += out_fifo
|
|
|
|
# Map core signals to stream, re-generate first/last delimiters from active signal.
|
|
out_data = Signal(32)
|
|
out_datak = Signal(4)
|
|
out_stall = Signal()
|
|
out_active = Signal()
|
|
out_active_d = Signal()
|
|
self.comb += out_fifo.sink.valid.eq(out_active_d)
|
|
self.sync += [
|
|
out_fifo.sink.data.eq(out_data),
|
|
out_fifo.sink.ctrl.eq(out_datak),
|
|
out_active_d.eq(out_active),
|
|
out_fifo.sink.first.eq(out_active & ~ out_active_d),
|
|
]
|
|
self.comb += out_fifo.sink.last.eq(~out_active & out_active_d)
|
|
|
|
# Connect FIFO to source.
|
|
self.comb += [
|
|
If(out_fifo.source.valid,
|
|
out_fifo.source.connect(source)
|
|
).Else(
|
|
source.valid.eq(1),
|
|
source.first.eq(0),
|
|
source.last.eq(0),
|
|
source.data.eq(0),
|
|
source.ctrl.eq(0),
|
|
)
|
|
]
|
|
|
|
# Daisho USB3 core -------------------------------------------------------------------------
|
|
usb3_top_params = dict(
|
|
i_clk = ClockSignal(),
|
|
i_reset_n = ~self.reset,
|
|
|
|
i_ltssm_state = ltssm_state,
|
|
|
|
i_in_data = aligner.source.data,
|
|
i_in_datak = aligner.source.ctrl,
|
|
i_in_active = aligner.source.valid,
|
|
|
|
o_out_data = out_data,
|
|
o_out_datak = out_datak,
|
|
o_out_active = out_active,
|
|
i_out_stall = 0, # FIXME
|
|
)
|
|
|
|
# Daisho USB3 core endpoinst ---------------------------------------------------------------
|
|
if with_endpoint:
|
|
self.submodules.usb3_control = usb3_control = USB3CoreControl()
|
|
usb3_top_params.update(
|
|
i_buf_in_addr = usb3_control.buf_in_addr,
|
|
i_buf_in_data = usb3_control.buf_in_data,
|
|
i_buf_in_wren = usb3_control.buf_in_wren,
|
|
o_buf_in_request = usb3_control.buf_in_request,
|
|
o_buf_in_ready = usb3_control.buf_in_ready,
|
|
i_buf_in_commit = usb3_control.buf_in_commit,
|
|
i_buf_in_commit_len = usb3_control.buf_in_commit_len,
|
|
o_buf_in_commit_ack = usb3_control.buf_in_commit_ack,
|
|
|
|
i_buf_out_addr = usb3_control.buf_out_addr,
|
|
o_buf_out_q = usb3_control.buf_out_q,
|
|
o_buf_out_len = usb3_control.buf_out_len,
|
|
o_buf_out_hasdata = usb3_control.buf_out_hasdata,
|
|
i_buf_out_arm = usb3_control.buf_out_arm,
|
|
o_buf_out_arm_ack = usb3_control.buf_out_arm_ack,
|
|
)
|
|
|
|
# Daisho USB3 instance ---------------------------------------------------------------------
|
|
self.specials += Instance("usb3_top_usb3_pipe", **usb3_top_params)
|
|
|
|
daisho_path = os.path.join(os.path.abspath(os.path.dirname(__file__)), "daisho")
|
|
platform.add_verilog_include_path(os.path.join(daisho_path))
|
|
platform.add_verilog_include_path(os.path.join(daisho_path, "usb3"))
|
|
platform.add_source_dir(os.path.join(daisho_path, "usb3"))
|