ttl_serdes: detect edges on short pulses

Edges on pulses shorter than the RTIO period were missed because the
reference sample and the last sample of the serdes word are the same.

This change enables detection of edges on pulses as short as the
serdes UI (and shorter as long as the pulse still hits a serdes sample
aperture).

In any RTIO period, only the leading event corresponding to the first
edge with slope according to sensitivity is registerd. If the channel is
sensitive to both rising and falling edges and if the pulse is contained
within an RTIO period, or if it is sensitive only to one edge slope and
there are multiple pulses in an RTIO period, only the leading event is
seen. Thus this possibility of lost events is still there. Only the
conditions under which loss occurs are reduced.

In testing with the kasli-ptb6 variant, this also improves resource
usage (a couple hundred LUT) and timing (0.1 ns WNS).
This commit is contained in:
Robert Jördens 2020-02-29 18:19:27 +01:00
parent e8b73876ab
commit ea79ba4622
2 changed files with 15 additions and 10 deletions

View File

@ -8,6 +8,10 @@ ARTIQ-6
Highlights: Highlights:
* Performance improvements:
- #1432: SERDES TTL inputs can now detect edges on pulses that are shorter
than the RTIO period
Breaking changes: Breaking changes:

View File

@ -7,7 +7,7 @@ from artiq.gateware.rtio import rtlink
def _mk_edges(w, direction): def _mk_edges(w, direction):
l = [(1 << i) - 1 for i in range(w)] l = [(1 << i) - 1 for i in range(w)]
if direction == "rising": if direction == "rising":
l = [2**w - 1 ^ x for x in l] l = [((1 << w) - 1) ^ x for x in l]
elif direction == "falling": elif direction == "falling":
pass pass
else: else:
@ -69,8 +69,8 @@ class InOut(Module):
# Output enable, for interfacing to external buffers. # Output enable, for interfacing to external buffers.
self.oe = Signal() self.oe = Signal()
# LSB of the input state (for edge detection; arbitrary choice, support for # input state exposed for edge_counter: latest serdes sample
# short pulses will need a more involved solution). # support for short pulses will need a more involved solution
self.input_state = Signal() self.input_state = Signal()
# # # # # #
@ -112,15 +112,16 @@ class InOut(Module):
i_d = Signal() i_d = Signal()
self.sync.rio_phy += [ self.sync.rio_phy += [
i_d.eq(i), i_d.eq(i),
self.rtlink.i.stb.eq(
sample |
(sensitivity[0] & ( i & ~i_d)) |
(sensitivity[1] & (~i & i_d))
),
self.rtlink.i.data.eq(i), self.rtlink.i.data.eq(i),
] ]
pe = PriorityEncoder(serdes_width) pe = PriorityEncoder(serdes_width)
self.submodules += pe self.submodules += pe
self.comb += pe.i.eq(serdes.i ^ Replicate(i_d, serdes_width)) self.comb += pe.i.eq(
self.sync.rio_phy += self.rtlink.i.fine_ts.eq(pe.o) (serdes.i ^ Cat(i_d, serdes.i)) & (
(serdes.i & Replicate(sensitivity[0], serdes_width)) |
(~serdes.i & Replicate(sensitivity[1], serdes_width))))
self.sync.rio_phy += [
self.rtlink.i.fine_ts.eq(pe.o),
self.rtlink.i.stb.eq(sample | ~pe.n),
]