diff --git a/artiq/frontend/artiq_ddb_template.py b/artiq/frontend/artiq_ddb_template.py index 052673e03..86452c607 100755 --- a/artiq/frontend/artiq_ddb_template.py +++ b/artiq/frontend/artiq_ddb_template.py @@ -485,6 +485,18 @@ class PeripheralManager: channel=rtio_offset) 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): processor = getattr(self, "process_"+str(peripheral["type"])) return processor(rtio_offset, peripheral) diff --git a/artiq/gateware/rtio/phy/fastlink.py b/artiq/gateware/rtio/phy/fastlink.py index 27f096a04..a7003c15e 100644 --- a/artiq/gateware/rtio/phy/fastlink.py +++ b/artiq/gateware/rtio/phy/fastlink.py @@ -30,6 +30,7 @@ class SerDes(Module): n_marker = n_frame//2 + 1 n_body = n_word*n_frame - n_marker - n_crc t_miso = 0 # miso sampling latency TODO + assert n_crc % n_mosi == 0 # frame data self.payload = Signal(n_body) @@ -40,8 +41,10 @@ class SerDes(Module): # # # - self.submodules.crc = LiteEthMACCRCEngine( - data_width=2*n_mosi, width=n_crc, polynom=poly) + self.submodules.crca = LiteEthMACCRCEngine( + data_width=n_mosi, width=n_crc, polynom=poly) + self.submodules.crcb = LiteEthMACCRCEngine( + data_width=n_mosi, width=n_crc, polynom=poly) words_ = [] j = 0 @@ -71,15 +74,17 @@ class SerDes(Module): # big shift register for mosi and sr = [Signal(t_frame, reset_less=True) for i in range(n_mosi)] assert len(Cat(sr)) == len(words) - sr_t = [sr[i % n_mosi][i//n_mosi] for i in range(len(words))] - data_t = ([d[0] for d in self.data[:-1]] + - [d[1] for d in self.data[:-1]]) + crc_insert = ([d[1] for d in self.data[:-1]] + + [d[0] for d in self.data[:-1]]) + crc_insert = Cat(crc_insert[-n_crc:]) 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(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)), ] self.sync.rio_phy += [ @@ -88,19 +93,20 @@ class SerDes(Module): clk.eq(Cat(clk[-2:], clk)), [sri.eq(Cat(C(0, 2), sri)) for sri in sr], miso_sr.eq(miso_sr_next), - self.crc.last.eq(self.crc.next), + self.crca.last.eq(self.crcb.next), i.eq(i + 1), If(self.stb, i.eq(0), clk.eq(clk.reset), - self.crc.last.eq(0), + self.crca.last.eq(0), # transpose, load [sri.eq(Cat(words[i::n_mosi])) for i, sri in enumerate(sr)], # unload miso self.readback.eq(Cat([miso_sr_next[t_miso + i*t_clk] for i in range(n_frame)])), # 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)): ddr = Signal() self.specials += [ - # d1 closer to q, LSB first + # d1 closer to q DDROutput(d[1], d[0], ddr, ClockSignal("rio_phy")), DifferentialOutput(ddr, pp, pn), ] ddr = Signal() self.specials += [ DifferentialInput(pins.miso, pins_n.miso, ddr), - # q1 closer to d, MSB first - DDRInput(ddr, self.data[-1][1], self.data[-1][0], + # q1 closer to d + DDRInput(ddr, self.data[-1][0], self.data[-1][1], ClockSignal("rio_phy")), ] diff --git a/artiq/gateware/test/rtio/test_fastlink.py b/artiq/gateware/test/rtio/test_fastlink.py index dd95120df..5b62c9aba 100644 --- a/artiq/gateware/test/rtio/test_fastlink.py +++ b/artiq/gateware/test/rtio/test_fastlink.py @@ -16,27 +16,27 @@ class TestPhaser(unittest.TestCase): def record_frame(self, frame): clk = 0 marker = 0 - state = "start" + stb = 0 while True: + if stb == 2: + frame.append((yield self.dut.data)) clk = (clk << 2) & 0xff clk |= (yield self.dut.data[0]) if clk == 0x0f: marker = (marker << 1) & 0x7f marker |= (yield self.dut.data[1]) & 1 if marker >> 1 == 0x01: - if state == "start": - state = "end" - elif state == "end": + stb += 1 + if stb >= 3: break yield - if state == "end": - data = yield from [(yield d) for d in self.dut.data] - frame.append(data) def test_frame(self): frame = [] + self.dut.comb += self.dut.payload.eq((1 << len(self.dut.payload)) - 1) 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([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]],