phaser: refactor link

This commit is contained in:
Robert Jördens 2020-08-22 11:46:41 +00:00
parent a34a647ec4
commit 3e99f1ce5a
2 changed files with 49 additions and 51 deletions

View File

@ -1,6 +1,6 @@
from migen import * from migen import *
from migen.genlib.cdc import MultiReg from migen.genlib.io import (DifferentialOutput, DifferentialInput,
from migen.genlib.io import DifferentialOutput, DifferentialInput, DDROutput DDROutput, DDRInput)
from misoc.cores.liteeth_mini.mac.crc import LiteEthMACCRCEngine from misoc.cores.liteeth_mini.mac.crc import LiteEthMACCRCEngine
from artiq.gateware.rtio import rtlink from artiq.gateware.rtio import rtlink
@ -17,16 +17,18 @@ class SerDes(Module):
* One return data lane at slower speed. * One return data lane at slower speed.
* n_frame//2 - 1 marker bits are used to provide framing. * n_frame//2 - 1 marker bits are used to provide framing.
* `n_frame` words per frame * `n_data` lanes
* `t_clk` bits per clk cycle with pattern `d_clk` * `t_clk` bits per clk cycle with pattern `d_clk`
* `n_crc` CRC bits per frame * `n_frame` words per frame
* `n_crc` CRC bits per frame for divisor poly `poly`
""" """
# pins # pins
self.data = [Signal(2) for _ in range(n_data)] self.data = [Signal(2) for _ in range(n_data)]
n_lanes = n_data - 2 # number of data lanes n_mosi = n_data - 2 # mosi lanes
n_word = n_lanes*t_clk n_word = n_mosi*t_clk # bits per word
t_frame = t_clk*n_frame//2 t_frame = t_clk*n_frame # frame duration
n_body = n_word*n_frame - (n_frame//2 + 1) - n_crc n_marker = n_frame//2 + 1
n_body = n_word*n_frame - n_marker - n_crc
t_miso = 0 # miso sampling latency TODO t_miso = 0 # miso sampling latency TODO
# frame data # frame data
@ -39,11 +41,11 @@ class SerDes(Module):
# # # # # #
self.submodules.crc = LiteEthMACCRCEngine( self.submodules.crc = LiteEthMACCRCEngine(
data_width=2*n_lanes, width=n_crc, polynom=poly) data_width=2*n_mosi, width=n_crc, polynom=poly)
words_ = [] words_ = []
j = 0 j = 0
# last, LSB to first, MSB # build from LSB to MSB because MSB first
for i in range(n_frame): # iterate over words for i in range(n_frame): # iterate over words
if i == 0: # data and checksum if i == 0: # data and checksum
k = n_word - n_crc k = n_word - n_crc
@ -64,65 +66,60 @@ class SerDes(Module):
self.comb += words.eq(words_) self.comb += words.eq(words_)
clk = Signal(t_clk, reset=d_clk) clk = Signal(t_clk, reset=d_clk)
i = Signal(max=t_frame) i = Signal(max=t_frame//2)
# big shift register for clk and mosi # big shift register for clk and mosi
sr = [Signal(t_frame*2 - n_crc//n_lanes, reset_less=True) sr = [Signal(t_frame - n_crc//n_mosi, reset_less=True)
for i in range(n_lanes)] for i in range(n_mosi)]
assert len(Cat(sr)) == len(words) assert len(Cat(sr)) == len(words)
# DDR bits for each register # DDR bits for each register
ddr_data = Cat([sri[-2] for sri in sr], [sri[-1] for sri in sr]) crc_data = [sri[-2] for sri in sr] + [sri[-1] for sri in sr]
self.comb += [
self.stb.eq(i == t_frame - 1),
# LiteETHMACCRCEngine takes data LSB first
self.crc.data[::-1].eq(ddr_data),
]
miso = Signal()
miso_sr = Signal(t_frame, reset_less=True) miso_sr = Signal(t_frame, reset_less=True)
miso_sr_next = Signal.like(miso_sr)
self.comb += [
self.stb.eq(i == t_frame//2 - 1),
# LiteETHMACCRCEngine takes data LSB first
self.crc.data.eq(Cat(reversed(crc_data))),
miso_sr_next.eq(Cat(self.data[-1], miso_sr)),
[di.eq(sri[-2:]) for di, sri in zip(self.data, [clk] + sr)],
]
self.sync.rio_phy += [ self.sync.rio_phy += [
# shift everything by two bits # shift everything by two bits
clk.eq(Cat(clk[-2:], clk)), [sri.eq(Cat(sri[-2:], sri)) for sri in [clk] + sr],
[sri[2:].eq(sri) for sri in sr], miso_sr.eq(miso_sr_next),
self.crc.last.eq(self.crc.next), self.crc.last.eq(self.crc.next),
miso_sr.eq(Cat(miso, miso_sr)),
i.eq(i + 1), i.eq(i + 1),
If(self.stb, If(self.stb,
i.eq(0), i.eq(0),
clk.eq(clk.reset), clk.eq(clk.reset),
self.crc.last.eq(0), self.crc.last.eq(0),
# transpose, load # transpose, load
Cat(sr).eq(Cat(words[mm::n_lanes] for mm in range(n_lanes))), [sri.eq(Cat(words[i::n_mosi])) for i, sri in enumerate(sr)],
self.readback.eq(Cat([miso_sr[int(round(t_miso + i*t_clk/2.))] # unload miso
self.readback.eq(Cat([miso_sr_next[t_miso + i*t_clk]
for i in range(n_frame)])), for i in range(n_frame)])),
), ),
If(i == t_frame - 2, If(i == t_frame//2 - 2,
# inject crc for the last cycle # inject crc for the last cycle
ddr_data.eq(self.crc.next), Cat(crc_data).eq(self.crc.next),
), ),
] ]
self.comb += [
self.data[0].eq(clk[-2:]),
[di.eq(sri[-2:]) for di, sri in zip(self.data[1:-1], sr)],
miso.eq(self.data[-1]),
]
class SerInterface(Module): class SerInterface(Module):
def __init__(self, pins, pins_n): def __init__(self, pins, pins_n):
n_data = 1 + len(pins.mosi) + 1 self.data = [Signal(2) for _ in range(2 + len(pins.mosi))]
self.data = [Signal(2) for _ in range(n_data)]
clk_ddr = Signal() for d, pp, pn in zip(self.data,
miso_reg = Signal() [pins.clk] + list(pins.mosi),
self.specials += [ [pins_n.clk] + list(pins_n.mosi)):
DDROutput(self.data[0][-1], self.data[0][-2],
clk_ddr, ClockSignal("rio_phy")),
DifferentialOutput(clk_ddr, pins.clk, pins_n.clk),
DifferentialInput(pins.miso, pins_n.miso, miso_reg),
MultiReg(miso_reg, self.data[-1], "rio_phy"),
]
for i in range(len(pins.mosi)):
ddr = Signal() ddr = Signal()
self.specials += [ self.specials += [
DDROutput(self.data[-1], self.data[-2], ddr, ClockSignal("rio_phy")), DDROutput(d[-1], d[-2], ddr, ClockSignal("rio_phy")),
DifferentialOutput(ddr, pins.mosi[i], pins_n.mosi[i]), DifferentialOutput(ddr, pp, pn),
]
ddr = Signal()
self.specials += [
DifferentialInput(pins.miso, pins_n.miso, ddr),
DDRInput(ddr, self.data[-1][-1], self.data[-1][-2],
ClockSignal("rio_phy")),
] ]

View File

@ -9,7 +9,7 @@ class Phaser(Module):
self.config = rtlink.Interface( self.config = rtlink.Interface(
rtlink.OInterface(data_width=8, address_width=8, rtlink.OInterface(data_width=8, address_width=8,
enable_replace=False), enable_replace=False),
rtlink.IInterface(data_width=8)) rtlink.IInterface(data_width=10))
self.data = rtlink.Interface( self.data = rtlink.Interface(
rtlink.OInterface(data_width=32, address_width=8, rtlink.OInterface(data_width=32, address_width=8,
enable_replace=True)) enable_replace=True))
@ -31,8 +31,9 @@ class Phaser(Module):
]) ])
n_channels = 2 n_channels = 2
n_samples = 8 n_samples = 8
body = [[(Signal(14), Signal(14)) for i in range(n_channels)] n_bits = 14
for j in range(n_samples)] body = [[(Signal(n_bits), Signal(n_bits))
for i in range(n_channels)] for j in range(n_samples)]
assert len(Cat(header.raw_bits(), body)) == \ assert len(Cat(header.raw_bits(), body)) == \
len(self.serializer.payload) len(self.serializer.payload)
self.comb += self.serializer.payload.eq(Cat(header.raw_bits(), body)) self.comb += self.serializer.payload.eq(Cat(header.raw_bits(), body))