Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: GlasgowEmbedded/glasgow
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: b9794b5428ee
Choose a base ref
...
head repository: GlasgowEmbedded/glasgow
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: ffdc0ae23980
Choose a head ref
  • 2 commits
  • 2 files changed
  • 1 contributor

Commits on Apr 7, 2019

  1. gateware.fx2_crossbar: rename FIFOs to reflect their function. NFC.

    Also, decouple access.simulation.multiplexer from FX2 gateware, since
    the former keeps breaking with changes to the latter, but the only
    thing it actually needs is a flush signal.
    whitequark committed Apr 7, 2019
    Copy the full SHA
    705033b View commit details
  2. Copy the full SHA
    ffdc0ae View commit details
Showing with 37 additions and 42 deletions.
  1. +2 −4 software/glasgow/access/simulation/multiplexer.py
  2. +35 −38 software/glasgow/gateware/fx2_crossbar.py
6 changes: 2 additions & 4 deletions software/glasgow/access/simulation/multiplexer.py
Original file line number Diff line number Diff line change
@@ -2,7 +2,6 @@
from migen.genlib.fifo import _FIFOInterface, AsyncFIFO, SyncFIFOBuffered

from .. import AccessMultiplexer, AccessMultiplexerInterface
from ...gateware.fx2_crossbar import _FIFOWithFlush


class SimulationMultiplexer(AccessMultiplexer):
@@ -52,9 +51,8 @@ def get_in_fifo(self, depth=512, auto_flush=False, clock_domain=None):
assert self.in_fifo is None

self.submodules.in_fifo = self._make_fifo(
crossbar_side="read", logic_side="write", cd_logic=clock_domain, depth=depth,
wrapper=lambda x: _FIFOWithFlush(x, asynchronous=clock_domain is not None,
auto_flush=auto_flush))
crossbar_side="read", logic_side="write", cd_logic=clock_domain, depth=depth)
self.in_fifo.flush = Signal(reset=auto_flush)
return self.in_fifo

def get_out_fifo(self, depth=512, clock_domain=None):
73 changes: 35 additions & 38 deletions software/glasgow/gateware/fx2_crossbar.py
Original file line number Diff line number Diff line change
@@ -107,7 +107,7 @@
# the FX2 and USB protocol into account. If we consider the host controller and OS as well, it
# becomes apparent that it is necessary to send maximum length packets.
#
# To understand the reason for this, consider that an application has to proivde the OS with
# To understand the reason for this, consider that an application has to provide the OS with
# a buffer to fill with data read from the USB device. This buffer has to be a multiple of
# the maximum packet size; if more data is returned, the extra data is discarded and an error
# is indicated. However, what happens if less data is returned? In that case, the OS returns
@@ -158,14 +158,18 @@


class _DummyFIFO(Module, _FIFOInterface):
"""
Placeholder for an FPGA-side FIFO that is not implemented, and is never readable or writable.
"""
def __init__(self, width):
super().__init__(width, 0)


class _FIFOWithOverflow(Module, _FIFOInterface):
class _OUTFIFO(Module, _FIFOInterface):
"""
A FIFO with an overflow buffer in front of it. Useful when the FIFO is fed from a pipeline
that reacts to the ``writable`` flag with a latency, and writes must not be lost.
A FIFO with an overflow buffer in front of it. This FIFO may be fed from a pipeline that
reacts to the ``writable`` flag with a latency up to the overflow buffer depth, and writes
will not be lost.
"""
def __init__(self, fifo, overflow_depth=2):
_FIFOInterface.__init__(self, fifo.width, fifo.depth)
@@ -202,11 +206,11 @@ def __init__(self, fifo, overflow_depth=2):
]


class _FIFOWithFlush(Module, _FIFOInterface):
class _INFIFO(Module, _FIFOInterface):
"""
A FIFO with a sideband flag indicating whether the FIFO has enough data to read from it yet.
Useful when the data read from the FIFO is packetized, but there is no particular framing
available to optimize the packet boundaries.
This FIFO may be used for packetizing the data read from the FIFO when there is no particular
framing available to optimize the packet boundaries.
"""
def __init__(self, fifo, asynchronous=False, auto_flush=True):
_FIFOInterface.__init__(self, fifo.width, fifo.depth)
@@ -292,16 +296,15 @@ class FX2Crossbar(Module):
def __init__(self, pads):
self.submodules.bus = _FX2Bus(pads)

self.out_fifos = Array([_FIFOWithOverflow(_DummyFIFO(width=8))
self.out_fifos = Array([_OUTFIFO(_DummyFIFO(width=8))
for _ in range(2)])
self. in_fifos = Array([_FIFOWithFlush(_DummyFIFO(width=8))
self. in_fifos = Array([_INFIFO(_DummyFIFO(width=8))
for _ in range(2)])

def do_finalize(self):
bus = self.bus
flag = Signal(4)
addr = Signal(2)
data = TSTriple(8)
fdoe = Signal()
sloe = Signal()
slrd = Signal()
@@ -315,8 +318,6 @@ def do_finalize(self):
rdy.eq(Cat([fifo.fifo.writable for fifo in self.out_fifos] +
[fifo.readable | fifo.queued for fifo in self. in_fifos]) &
flag),
self.out_fifos[addr[0]].din.eq(bus.fd_t.i),
bus.fd_t.o.eq(self.in_fifos[addr[0]].dout),
bus.fd_t.oe.eq(fdoe),
bus.sloe_t.oe.eq(1),
bus.sloe_t.o.eq(~sloe),
@@ -328,19 +329,26 @@ def do_finalize(self):
bus.pktend_t.o.eq(~pend),
]

# Derive the control signals for the FPGA-side FIFOs from the FX2 bus control signals.
# This is done independently from the main FSM because registers in the FX2 output path
# add latency, complicating logic.
slrd_r = Signal()
# Delay the FX2 bus control signals, taking into account the roundtrip latency.
slrd_r = Signal.like(slrd)
addr_r = Signal.like(addr)
self.sync += [
slrd_r.eq(slrd),
addr_r.eq(addr),
]

sel_flag = flag.part(addr, 1)
sel_in_fifo = self.in_fifos [addr [0]]
sel_out_fifo = self.out_fifos[addr_r[0]]

self.comb += [
bus.fd_t.o.eq(sel_in_fifo.dout),
sel_out_fifo.din.eq(bus.fd_t.i),
If(addr[1],
self.in_fifos [addr[0]].re.eq(slwr),
self.in_fifos [addr[0]].flushed.eq(pend),
sel_in_fifo.re.eq(slwr),
sel_in_fifo.flushed.eq(pend),
).Else(
self.out_fifos[addr[0]].we.eq(slrd_r & flag.part(addr, 1)),
sel_out_fifo.we.eq(slrd_r & sel_flag),
)
]

@@ -379,20 +387,15 @@ def do_finalize(self):
)
self.fsm.act("SETUP",
If(addr[1],
NextState("IN-SETUP")
NextState("IN-XFER")
).Else(
NextState("OUT-SETUP")
NextState("OUT-XFER")
)
)

# IN endpoint handling
self.fsm.act("IN-SETUP",
NextState("IN-XFER")
)
self.fsm.act("IN-XFER",
If(flag.part(addr, 1) & self.in_fifos[addr[0]].readable,
If(sel_flag & sel_in_fifo.readable,
slwr.eq(1)
).Elif(~flag.part(addr, 1) & ~self.in_fifos[addr[0]].readable,
).Elif(~sel_flag & ~sel_in_fifo.readable,
# The ~FULL flag went down, and it goes down one sample earlier than the actual
# FULL condition. So we have one more byte free. However, the FPGA-side FIFO
# became empty simultaneously.
@@ -403,7 +406,7 @@ def do_finalize(self):
#
# This shouldn't cause any problems.
NextState("IN-PKTEND")
).Elif(flag.part(addr, 1) & self.in_fifos[addr[0]].queued,
).Elif(sel_flag & sel_in_fifo.queued,
# The FX2-side FIFO is not full yet, but the flush flag is asserted.
# Commit the short packet.
NextState("IN-PKTEND")
@@ -420,14 +423,8 @@ def do_finalize(self):
pend.eq(1),
NextState("NEXT")
)

# OUT endpoint handling
self.fsm.act("OUT-SETUP",
slrd.eq(1),
NextState("OUT-XFER")
)
self.fsm.act("OUT-XFER",
If(flag.part(addr, 1) & self.out_fifos[addr[0]].fifo.writable,
If(sel_flag & sel_out_fifo.fifo.writable,
slrd.eq(1),
).Else(
NextState("NEXT")
@@ -483,7 +480,7 @@ def get_out_fifo(self, n, depth=512, clock_domain=None, reset=None):
cd_logic=clock_domain,
reset=reset,
depth=depth,
wrapper=lambda x: _FIFOWithOverflow(x))
wrapper=lambda x: _OUTFIFO(x))
self.out_fifos[n] = fifo
return fifo

@@ -496,7 +493,7 @@ def get_in_fifo(self, n, depth=512, auto_flush=True, clock_domain=None, reset=No
cd_logic=clock_domain,
reset=reset,
depth=depth,
wrapper=lambda x: _FIFOWithFlush(x,
wrapper=lambda x: _INFIFO(x,
asynchronous=clock_domain is not None,
auto_flush=auto_flush))
self.in_fifos[n] = fifo