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: m-labs/artiq
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 905abd6e27a7
Choose a base ref
...
head repository: m-labs/artiq
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 117b361a06e1
Choose a head ref
  • 8 commits
  • 7 files changed
  • 2 contributors

Commits on Jul 26, 2015

  1. rtio: add SERDES TTL (WIP)

    fallen authored and sbourdeauducq committed Jul 26, 2015
    Copy the full SHA
    d90dff4 View commit details
  2. Copy the full SHA
    940aa81 View commit details
  3. Copy the full SHA
    f68d5cb View commit details

Commits on Jul 27, 2015

  1. Copy the full SHA
    d3f05e4 View commit details
  2. Copy the full SHA
    5b50f5f View commit details
  3. Copy the full SHA
    fe6a5c4 View commit details
  4. Copy the full SHA
    3573fd0 View commit details
  5. Copy the full SHA
    117b361 View commit details
15 changes: 9 additions & 6 deletions artiq/gateware/rtio/core.py
Original file line number Diff line number Diff line change
@@ -300,8 +300,7 @@ def __init__(self, chan_sel_width,


class RTIO(Module):
def __init__(self, channels, clk_freq, full_ts_width=63,
guard_io_cycles=20):
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)
address_width = max(rtlink.get_address_width(c.interface)
@@ -329,11 +328,15 @@ def __init__(self, channels, clk_freq, full_ts_width=63,
self.cd_rsys.rst.eq(self.kcsrs.reset.storage)
]
self.comb += self.cd_rio.clk.eq(ClockSignal("rtio"))
self.specials += AsyncResetSynchronizer(self.cd_rio,
self.kcsrs.reset.storage)
self.specials += AsyncResetSynchronizer(
self.cd_rio,
self.kcsrs.reset.storage | ResetSignal("rtio",
allow_resetless=True))
self.comb += self.cd_rio_phy.clk.eq(ClockSignal("rtio"))
self.specials += AsyncResetSynchronizer(self.cd_rio_phy,
self.kcsrs.reset_phy.storage)
self.specials += AsyncResetSynchronizer(
self.cd_rio_phy,
self.kcsrs.reset_phy.storage | ResetSignal("rtio",
allow_resetless=True))

# Managers
self.submodules.counter = _RTIOCounter(full_ts_width - fine_ts_width)
70 changes: 70 additions & 0 deletions artiq/gateware/rtio/phy/ttl_serdes_7series.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
from migen.fhdl.std import *

from artiq.gateware.rtio.phy import ttl_serdes_generic


class _OSERDESE2_8X(Module):
def __init__(self, pad):
self.o = Signal(8)
self.t_in = Signal()
self.t_out = Signal()

# # #

o = self.o
self.specials += Instance("OSERDESE2",
p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF",
p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1,
o_OQ=pad, o_TQ=self.t_out,
i_CLK=ClockSignal("rtiox4"),
i_CLKDIV=ClockSignal("rio_phy"),
i_D1=o[0], i_D2=o[1], i_D3=o[2], i_D4=o[3],
i_D5=o[4], i_D6=o[5], i_D7=o[6], i_D8=o[7],
i_TCE=1, i_OCE=1, i_RST=0,
i_T1=self.t_in)


class _IOSERDESE2_8X(Module):
def __init__(self, pad):
self.o = Signal(8)
self.i = Signal(8)
self.oe = Signal()

# # #

pad_i = Signal()
pad_o = Signal()
i = self.i
self.specials += Instance("ISERDESE2", p_DATA_RATE="DDR",
p_DATA_WIDTH=8,
p_INTERFACE_TYPE="NETWORKING", p_NUM_CE=1,
o_Q1=i[7], o_Q2=i[6], o_Q3=i[5], o_Q4=i[4],
o_Q5=i[3], o_Q6=i[2], o_Q7=i[1], o_Q8=i[0],
i_D=pad_i,
i_CLK=ClockSignal("rtiox4"),
i_CLKB=~ClockSignal("rtiox4"),
i_CE1=1, i_RST=0,
i_CLKDIV=ClockSignal("rio_phy"))
oserdes = _OSERDESE2_8X(pad_o)
self.submodules += oserdes
self.specials += Instance("IOBUF",
i_I=pad_o, o_O=pad_i, i_T=oserdes.t_out,
io_IO=pad)
self.comb += [
oserdes.t_in.eq(~self.oe),
oserdes.o.eq(self.o)
]


class Output_8X(ttl_serdes_generic.Output):
def __init__(self, pad):
serdes = _OSERDESE2_8X(pad)
self.submodules += serdes
ttl_serdes_generic.Output.__init__(self, serdes)


class Inout_8X(ttl_serdes_generic.Inout):
def __init__(self, pad):
serdes = _IOSERDESE2_8X(pad)
self.submodules += serdes
ttl_serdes_generic.Inout.__init__(self, serdes)
273 changes: 273 additions & 0 deletions artiq/gateware/rtio/phy/ttl_serdes_generic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,273 @@
from migen.fhdl.std import *
from migen.genlib.coding import PriorityEncoder

from artiq.gateware.rtio import rtlink


def _mk_edges(w, direction):
l = [(1 << i) - 1 for i in range(w)]
if direction == "rising":
l = [2**w - 1 ^ x for x in l]
elif direction == "falling":
pass
else:
raise ValueError
return l


class _SerdesDriver(Module):
def __init__(self, serdes_o, stb, data, fine_ts, override_en, override_o):
previous_data = Signal()
serdes_width = flen(serdes_o)
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]),
).Else(
serdes_o.eq(Replicate(previous_data, serdes_width)),
)
)
]


class Output(Module):
def __init__(self, serdes):
self.rtlink = rtlink.Interface(
rtlink.OInterface(1, fine_ts_width=log2_int(flen(serdes.o))))
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)


class Inout(Module):
def __init__(self, serdes):
serdes_width = flen(serdes.o)
assert flen(serdes.i) == serdes_width
self.rtlink = rtlink.Interface(
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]
override_en = Signal()
override_o = Signal()
override_oe = Signal()
self.overrides = [override_en, override_o, override_oe]

# # #

# 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()
self.sync.rio_phy += [
If(self.rtlink.o.stb & (self.rtlink.o.address == 1),
oe_k.eq(self.rtlink.o.data[0])),
If(override_en,
serdes.oe.eq(override_oe)
).Else(
serdes.oe.eq(oe_k)
)
]

# Input
sensitivity = Signal(2)
self.sync.rio += If(self.rtlink.o.stb & (self.rtlink.o.address == 2),
sensitivity.eq(self.rtlink.o.data))

i = serdes.i[-1]
i_d = Signal()
self.sync.rio_phy += [
i_d.eq(i),
self.rtlink.i.stb.eq(
(sensitivity[0] & ( i & ~i_d)) |
(sensitivity[1] & (~i & i_d))
),
self.rtlink.i.data.eq(i),
]

pe = PriorityEncoder(serdes_width)
self.submodules += pe
self.comb += pe.i.eq(serdes.i ^ Replicate(i_d, serdes_width))
self.sync.rio_phy += self.rtlink.i.fine_ts.eq(pe.o)


class _FakeSerdes(Module):
def __init__(self):
self.o = Signal(8)
self.i = Signal(8)
self.oe = Signal()


class _OutputTB(Module):
def __init__(self):
serdes = _FakeSerdes()
self.submodules.dut = RenameClockDomains(Output(serdes),
{"rio_phy": "sys"})

def gen_simulation(self, selfp):
selfp.dut.rtlink.o.data = 1
selfp.dut.rtlink.o.fine_ts = 1
selfp.dut.rtlink.o.stb = 1
yield
selfp.dut.rtlink.o.stb = 0
yield
selfp.dut.rtlink.o.data = 0
selfp.dut.rtlink.o.fine_ts = 2
selfp.dut.rtlink.o.stb = 1
yield
yield
selfp.dut.rtlink.o.data = 1
selfp.dut.rtlink.o.fine_ts = 7
selfp.dut.rtlink.o.stb = 1
for _ in range(6):
# note that stb stays active; output should not change
yield


class _InoutTB(Module):
def __init__(self):
self.serdes = _FakeSerdes()
self.submodules.dut = RenameClockDomains(Inout(self.serdes),
{"rio_phy": "sys",
"rio": "sys"})

def check_input(self, selfp, stb, fine_ts=None):
if stb != selfp.dut.rtlink.i.stb:
print("KO rtlink.i.stb should be {} but is {}"
.format(stb, selfp.dut.rtlink.i.stb))
elif fine_ts is not None and fine_ts != selfp.dut.rtlink.i.fine_ts:
print("KO rtlink.i.fine_ts should be {} but is {}"
.format(fine_ts, selfp.dut.rtlink.i.fine_ts))
else:
print("OK")

def check_output(self, selfp, data):
if selfp.serdes.o != data:
print("KO io.o should be {} but is {}".format(data, selfp.serdes.o))
else:
print("OK")

def check_output_enable(self, selfp, oe):
if selfp.serdes.oe != oe:
print("KO io.oe should be {} but is {}".format(oe, selfp.serdes.oe))
else:
print("OK")

def gen_simulation(self, selfp):
selfp.dut.rtlink.o.address = 2
selfp.dut.rtlink.o.data = 0b11
selfp.dut.rtlink.o.stb = 1 # set sensitivity to rising + falling
yield
selfp.dut.rtlink.o.stb = 0

self.check_output_enable(selfp, 0)
yield

selfp.serdes.i = 0b11111110 # rising edge at fine_ts = 1
yield
selfp.serdes.i = 0b11111111
yield
self.check_input(selfp, stb=1, fine_ts=1)

selfp.serdes.i = 0b01111111 # falling edge at fine_ts = 7
yield
selfp.serdes.i = 0b00000000
yield
self.check_input(selfp, stb=1, fine_ts=7)

selfp.serdes.i = 0b11000000 # rising edge at fine_ts = 6
yield
selfp.serdes.i = 0b11111111
yield
self.check_input(selfp, stb=1, fine_ts=6)

selfp.dut.rtlink.o.address = 2
selfp.dut.rtlink.o.data = 0b11
selfp.dut.rtlink.o.stb = 1 # set sensitivity to rising only
yield
selfp.dut.rtlink.o.stb = 0
yield

selfp.serdes.i = 0b00001111 # falling edge at fine_ts = 4
yield
self.check_input(selfp, stb=0) # no strobe, sensitivity is rising edge

selfp.serdes.i = 0b11110000 # rising edge at fine_ts = 4
yield
self.check_input(selfp, stb=1, fine_ts=4)

selfp.dut.rtlink.o.address = 1
selfp.dut.rtlink.o.data = 1
selfp.dut.rtlink.o.stb = 1 # set Output Enable to 1
yield
selfp.dut.rtlink.o.stb = 0
yield
yield
self.check_output_enable(selfp, 1)

selfp.dut.rtlink.o.address = 0
selfp.dut.rtlink.o.data = 1
selfp.dut.rtlink.o.fine_ts = 3
selfp.dut.rtlink.o.stb = 1 # rising edge at fine_ts = 3
yield
selfp.dut.rtlink.o.stb = 0
yield
self.check_output(selfp, data=0b11111000)

yield
self.check_output(selfp, data=0xFF) # stays at 1

selfp.dut.rtlink.o.data = 0
selfp.dut.rtlink.o.fine_ts = 0
selfp.dut.rtlink.o.stb = 1 # falling edge at fine_ts = 0
yield
selfp.dut.rtlink.o.stb = 0
yield
self.check_output(selfp, data=0)

yield
self.check_output(selfp, data=0)

selfp.dut.rtlink.o.data = 1
selfp.dut.rtlink.o.fine_ts = 7
selfp.dut.rtlink.o.stb = 1 # rising edge at fine_ts = 7
yield
selfp.dut.rtlink.o.stb = 0
yield
self.check_output(selfp, data=0b10000000)


if __name__ == "__main__":
import sys
from migen.sim.generic import Simulator, TopLevel

if len(sys.argv) != 2:
print("Incorrect command line")
sys.exit(1)

cls = {
"output": _OutputTB,
"inout": _InoutTB
}[sys.argv[1]]

with Simulator(cls(), TopLevel("top.vcd", clk_period=int(1/0.125))) as s:
s.run()
Loading