phaser: ddb template, split crc

This commit is contained in:
Robert Jördens 2020-08-24 14:51:50 +00:00
parent 11c9def589
commit bcefb06e19
3 changed files with 38 additions and 20 deletions

View File

@ -485,6 +485,18 @@ class PeripheralManager:
channel=rtio_offset) channel=rtio_offset)
return 1 return 1
def process_phaser(self, rtio_offset, peripheral):
self.gen("""
device_db["{name}"] = {{
"type": "local",
"module": "artiq.coredevice.phaser",
"class": "Phaser",
"arguments": {{"channel": 0x{channel:06x}}}
}}""",
name=self.get_name("phaser"),
channel=rtio_offset)
return 2
def process(self, rtio_offset, peripheral): def process(self, rtio_offset, peripheral):
processor = getattr(self, "process_"+str(peripheral["type"])) processor = getattr(self, "process_"+str(peripheral["type"]))
return processor(rtio_offset, peripheral) return processor(rtio_offset, peripheral)

View File

@ -30,6 +30,7 @@ class SerDes(Module):
n_marker = n_frame//2 + 1 n_marker = n_frame//2 + 1
n_body = n_word*n_frame - n_marker - n_crc n_body = n_word*n_frame - n_marker - n_crc
t_miso = 0 # miso sampling latency TODO t_miso = 0 # miso sampling latency TODO
assert n_crc % n_mosi == 0
# frame data # frame data
self.payload = Signal(n_body) self.payload = Signal(n_body)
@ -40,8 +41,10 @@ class SerDes(Module):
# # # # # #
self.submodules.crc = LiteEthMACCRCEngine( self.submodules.crca = LiteEthMACCRCEngine(
data_width=2*n_mosi, width=n_crc, polynom=poly) data_width=n_mosi, width=n_crc, polynom=poly)
self.submodules.crcb = LiteEthMACCRCEngine(
data_width=n_mosi, width=n_crc, polynom=poly)
words_ = [] words_ = []
j = 0 j = 0
@ -71,15 +74,17 @@ class SerDes(Module):
# big shift register for mosi and # big shift register for mosi and
sr = [Signal(t_frame, reset_less=True) for i in range(n_mosi)] sr = [Signal(t_frame, reset_less=True) for i in range(n_mosi)]
assert len(Cat(sr)) == len(words) assert len(Cat(sr)) == len(words)
sr_t = [sr[i % n_mosi][i//n_mosi] for i in range(len(words))] crc_insert = ([d[1] for d in self.data[:-1]] +
data_t = ([d[0] for d in self.data[:-1]] + [d[0] for d in self.data[:-1]])
[d[1] for d in self.data[:-1]]) crc_insert = Cat(crc_insert[-n_crc:])
miso_sr = Signal(t_frame, reset_less=True) miso_sr = Signal(t_frame, reset_less=True)
miso_sr_next = Signal.like(miso_sr) miso_sr_next = Signal.like(miso_sr)
self.comb += [ self.comb += [
self.stb.eq(i == t_frame//2 - 1), self.stb.eq(i == t_frame//2 - 1),
# LiteETHMACCRCEngine takes data LSB first # LiteETHMACCRCEngine takes data LSB first
self.crc.data.eq(Cat(reversed(sr_t[-2*n_mosi:]))), self.crca.data.eq(Cat([sri[-1] for sri in sr[::-1]])),
self.crcb.data.eq(Cat([sri[-2] for sri in sr[::-1]])),
self.crcb.last.eq(self.crca.next),
miso_sr_next.eq(Cat(self.data[-1], miso_sr)), miso_sr_next.eq(Cat(self.data[-1], miso_sr)),
] ]
self.sync.rio_phy += [ self.sync.rio_phy += [
@ -88,19 +93,20 @@ class SerDes(Module):
clk.eq(Cat(clk[-2:], clk)), clk.eq(Cat(clk[-2:], clk)),
[sri.eq(Cat(C(0, 2), sri)) for sri in sr], [sri.eq(Cat(C(0, 2), sri)) for sri in sr],
miso_sr.eq(miso_sr_next), miso_sr.eq(miso_sr_next),
self.crc.last.eq(self.crc.next), self.crca.last.eq(self.crcb.next),
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.crca.last.eq(0),
# transpose, load # transpose, load
[sri.eq(Cat(words[i::n_mosi])) for i, sri in enumerate(sr)], [sri.eq(Cat(words[i::n_mosi])) for i, sri in enumerate(sr)],
# unload miso # unload miso
self.readback.eq(Cat([miso_sr_next[t_miso + i*t_clk] self.readback.eq(Cat([miso_sr_next[t_miso + i*t_clk]
for i in range(n_frame)])), for i in range(n_frame)])),
# inject crc for the last cycle # inject crc for the last cycle
Cat(data_t[-n_crc:]).eq(self.crc.next), crc_insert.eq(self.crca.next if n_crc // n_mosi == 1
else self.crcb.next),
), ),
] ]
@ -114,14 +120,14 @@ class SerInterface(Module):
[pins_n.clk] + list(pins_n.mosi)): [pins_n.clk] + list(pins_n.mosi)):
ddr = Signal() ddr = Signal()
self.specials += [ self.specials += [
# d1 closer to q, LSB first # d1 closer to q
DDROutput(d[1], d[0], ddr, ClockSignal("rio_phy")), DDROutput(d[1], d[0], ddr, ClockSignal("rio_phy")),
DifferentialOutput(ddr, pp, pn), DifferentialOutput(ddr, pp, pn),
] ]
ddr = Signal() ddr = Signal()
self.specials += [ self.specials += [
DifferentialInput(pins.miso, pins_n.miso, ddr), DifferentialInput(pins.miso, pins_n.miso, ddr),
# q1 closer to d, MSB first # q1 closer to d
DDRInput(ddr, self.data[-1][1], self.data[-1][0], DDRInput(ddr, self.data[-1][0], self.data[-1][1],
ClockSignal("rio_phy")), ClockSignal("rio_phy")),
] ]

View File

@ -16,27 +16,27 @@ class TestPhaser(unittest.TestCase):
def record_frame(self, frame): def record_frame(self, frame):
clk = 0 clk = 0
marker = 0 marker = 0
state = "start" stb = 0
while True: while True:
if stb == 2:
frame.append((yield self.dut.data))
clk = (clk << 2) & 0xff clk = (clk << 2) & 0xff
clk |= (yield self.dut.data[0]) clk |= (yield self.dut.data[0])
if clk == 0x0f: if clk == 0x0f:
marker = (marker << 1) & 0x7f marker = (marker << 1) & 0x7f
marker |= (yield self.dut.data[1]) & 1 marker |= (yield self.dut.data[1]) & 1
if marker >> 1 == 0x01: if marker >> 1 == 0x01:
if state == "start": stb += 1
state = "end" if stb >= 3:
elif state == "end":
break break
yield yield
if state == "end":
data = yield from [(yield d) for d in self.dut.data]
frame.append(data)
def test_frame(self): def test_frame(self):
frame = [] frame = []
self.dut.comb += self.dut.payload.eq((1 << len(self.dut.payload)) - 1)
run_simulation(self.dut, self.record_frame(frame), run_simulation(self.dut, self.record_frame(frame),
clocks={n: 2 for n in ["sys", "rio", "rio_phy"]}) clocks={n: 2 for n in ["sys", "rio", "rio_phy"]},
vcd_name="fastlink.vcd")
self.assertEqual(len(frame), 8*10//2) self.assertEqual(len(frame), 8*10//2)
self.assertEqual([d[0] for d in frame], [0, 0, 3, 3] * 10) self.assertEqual([d[0] for d in frame], [0, 0, 3, 3] * 10)
self.assertEqual([d[1] & 1 for d in frame[4*4 - 1:10*4 - 1:4]], self.assertEqual([d[1] & 1 for d in frame[4*4 - 1:10*4 - 1:4]],