artiq/artiq/gateware/rtio/phy/ttl_serdes_generic.py

128 lines
4.0 KiB
Python
Raw Normal View History

2015-11-04 00:35:03 +08:00
from migen import *
2015-07-26 17:40:18 +08:00
from migen.genlib.coding import PriorityEncoder
2015-07-27 00:01:41 +08:00
from artiq.gateware.rtio import rtlink
2015-07-26 17:40:18 +08:00
2015-07-27 00:01:41 +08:00
def _mk_edges(w, direction):
l = [(1 << i) - 1 for i in range(w)]
if direction == "rising":
l = [((1 << w) - 1) ^ x for x in l]
2015-07-27 00:01:41 +08:00
elif direction == "falling":
pass
else:
raise ValueError
return l
2015-07-26 17:40:18 +08:00
2015-07-27 00:01:41 +08:00
class _SerdesDriver(Module):
def __init__(self, serdes_o, stb, data, fine_ts, override_en, override_o):
previous_data = Signal()
2015-11-04 00:35:03 +08:00
serdes_width = len(serdes_o)
2015-07-27 00:01:41 +08:00
edges = Array(_mk_edges(serdes_width, "rising"))
edges_n = Array(_mk_edges(serdes_width, "falling"))
self.sync.rio_phy += [
If(stb, previous_data.eq(data)),
If(override_en,
serdes_o.eq(Replicate(override_o, serdes_width))
).Else(
If(stb & ~previous_data & data,
serdes_o.eq(edges[fine_ts]),
).Elif(stb & previous_data & ~data,
serdes_o.eq(edges_n[fine_ts]),
2015-07-26 17:40:18 +08:00
).Else(
2015-07-27 00:01:41 +08:00
serdes_o.eq(Replicate(previous_data, serdes_width)),
2015-07-26 17:40:18 +08:00
)
2015-07-27 00:01:41 +08:00
)
2015-07-26 17:40:18 +08:00
]
2015-07-27 00:01:41 +08:00
class Output(Module):
def __init__(self, serdes):
self.rtlink = rtlink.Interface(
2015-11-04 00:35:03 +08:00
rtlink.OInterface(1, fine_ts_width=log2_int(len(serdes.o))))
2015-07-27 00:01:41 +08:00
self.probes = [serdes.o[-1]]
override_en = Signal()
override_o = Signal()
self.overrides = [override_en, override_o]
# # #
self.submodules += _SerdesDriver(
serdes.o,
self.rtlink.o.stb, self.rtlink.o.data, self.rtlink.o.fine_ts,
override_en, override_o)
2015-07-26 17:40:18 +08:00
2017-03-14 14:18:55 +08:00
class InOut(Module):
2015-07-27 00:01:41 +08:00
def __init__(self, serdes):
2015-11-04 00:35:03 +08:00
serdes_width = len(serdes.o)
assert len(serdes.i) == serdes_width
2015-07-26 17:40:18 +08:00
self.rtlink = rtlink.Interface(
2015-07-27 00:01:41 +08:00
rtlink.OInterface(2, 2, fine_ts_width=log2_int(serdes_width)),
rtlink.IInterface(1, fine_ts_width=log2_int(serdes_width)))
self.probes = [serdes.i[-1], serdes.oe]
2015-07-26 17:40:18 +08:00
override_en = Signal()
override_o = Signal()
override_oe = Signal()
self.overrides = [override_en, override_o, override_oe]
2019-10-16 18:48:20 +08:00
# Output enable, for interfacing to external buffers.
self.oe = Signal()
# input state exposed for edge_counter: latest serdes sample
# support for short pulses will need a more involved solution
2018-12-11 06:21:26 +08:00
self.input_state = Signal()
2015-07-27 00:01:41 +08:00
# # #
# Output
self.submodules += _SerdesDriver(
serdes_o=serdes.o,
stb=self.rtlink.o.stb & (self.rtlink.o.address == 0),
data=self.rtlink.o.data[0],
fine_ts=self.rtlink.o.fine_ts,
override_en=override_en, override_o=override_o)
oe_k = Signal()
2019-10-16 18:48:20 +08:00
self.oe.attr.add("no_retiming")
2015-07-26 17:40:18 +08:00
self.sync.rio_phy += [
2015-07-27 00:01:41 +08:00
If(self.rtlink.o.stb & (self.rtlink.o.address == 1),
oe_k.eq(self.rtlink.o.data[0])),
2015-07-26 17:40:18 +08:00
If(override_en,
2019-10-16 18:48:20 +08:00
self.oe.eq(override_oe)
2015-07-27 00:01:41 +08:00
).Else(
2019-10-16 18:48:20 +08:00
self.oe.eq(oe_k)
2015-07-27 00:01:41 +08:00
)
2015-07-26 17:40:18 +08:00
]
2019-10-16 18:48:20 +08:00
self.comb += serdes.oe.eq(self.oe)
2015-07-26 17:40:18 +08:00
2015-07-27 00:01:41 +08:00
# Input
sensitivity = Signal(2)
sample = Signal()
self.sync.rio += [
sample.eq(0),
If(self.rtlink.o.stb & self.rtlink.o.address[1],
sensitivity.eq(self.rtlink.o.data),
If(self.rtlink.o.address[0], sample.eq(1))
)
]
2015-07-27 00:01:41 +08:00
i = serdes.i[-1]
2018-12-11 06:21:26 +08:00
self.comb += self.input_state.eq(i)
2015-07-27 00:01:41 +08:00
i_d = Signal()
self.sync.rio_phy += [
i_d.eq(i),
self.rtlink.i.data.eq(i),
2015-07-26 17:40:18 +08:00
]
2015-07-27 00:01:41 +08:00
pe = PriorityEncoder(serdes_width)
self.submodules += pe
self.comb += pe.i.eq(
(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),
]