diff --git a/artiq/gateware/drtio/link_layer.py b/artiq/gateware/drtio/link_layer.py index 0b6eba04f..aac149b4f 100644 --- a/artiq/gateware/drtio/link_layer.py +++ b/artiq/gateware/drtio/link_layer.py @@ -5,24 +5,6 @@ from migen import * class Scrambler(Module): - def __init__(self, n_io, n_state=23, taps=[17, 22]): - self.i = Signal(n_io) - self.o = Signal(n_io) - - # # # - - state = Signal(n_state, reset=1) - curval = [state[i] for i in range(n_state)] - for i in reversed(range(n_io)): - out = self.i[i] ^ reduce(xor, [curval[tap] for tap in taps]) - self.sync += self.o[i].eq(out) - curval.insert(0, out) - curval.pop() - - self.sync += state.eq(Cat(*curval[:n_state])) - - -class Descrambler(Module): def __init__(self, n_io, n_state=23, taps=[17, 22]): self.i = Signal(n_io) self.o = Signal(n_io) @@ -33,8 +15,8 @@ class Descrambler(Module): curval = [state[i] for i in range(n_state)] for i in reversed(range(n_io)): flip = reduce(xor, [curval[tap] for tap in taps]) - self.sync += self.o[i].eq(self.i[i] ^ flip) - curval.insert(0, self.i[i]) + self.sync += self.o[i].eq(flip ^ self.i[i]) + curval.insert(0, flip) curval.pop() self.sync += state.eq(Cat(*curval[:n_state])) @@ -70,7 +52,7 @@ class LinkLayerTX(Module): # the following meanings: # 100 idle/auxiliary framing # 0AB 2 bits of auxiliary data - aux_scrambler = CEInserter()(Scrambler(3*nwords)) + aux_scrambler = ResetInserter()(CEInserter()(Scrambler(3*nwords))) self.submodules += aux_scrambler aux_data_ctl = [] for i in range(nwords): @@ -82,6 +64,7 @@ class LinkLayerTX(Module): ).Else( aux_scrambler.i.eq(Replicate(0b100, nwords)) ), + aux_scrambler.reset.eq(self.link_init), aux_scrambler.ce.eq(~self.rt_frame), self.aux_ack.eq(~self.rt_frame) ] @@ -98,10 +81,11 @@ class LinkLayerTX(Module): # Real-time traffic uses data characters and is framed by the special # characters of auxiliary traffic. RT traffic is also scrambled. - rt_scrambler = CEInserter()(Scrambler(8*nwords)) + rt_scrambler = ResetInserter()(CEInserter()(Scrambler(8*nwords))) self.submodules += rt_scrambler self.comb += [ rt_scrambler.i.eq(self.rt_data), + rt_scrambler.reset.eq(self.link_init), rt_scrambler.ce.eq(self.rt_frame) ] rt_frame_r = Signal() @@ -153,8 +137,8 @@ class LinkLayerRX(Module): # # # - aux_descrambler = CEInserter()(Descrambler(2*nwords)) - rt_descrambler = CEInserter()(Descrambler(8*nwords)) + aux_descrambler = ResetInserter()(CEInserter()(Scrambler(2*nwords))) + rt_descrambler = ResetInserter()(CEInserter()(Scrambler(8*nwords))) self.submodules += aux_descrambler, rt_descrambler self.comb += [ self.aux_frame.eq(~aux_descrambler.o[2]), @@ -173,7 +157,9 @@ class LinkLayerRX(Module): self.comb += [ If(decoders[0].k, If((decoders[0].d == K(28, 7)) | (decoders[0].d == K(29, 7)), - link_init_d.eq(1) + link_init_d.eq(1), + aux_descrambler.reset.eq(1), + rt_descrambler.reset.eq(1) ), aux_descrambler.ce.eq(1) ).Else( diff --git a/artiq/test/gateware/drtio/test_link_layer.py b/artiq/test/gateware/drtio/test_link_layer.py index 4e1906f52..bb3b71ba5 100644 --- a/artiq/test/gateware/drtio/test_link_layer.py +++ b/artiq/test/gateware/drtio/test_link_layer.py @@ -6,7 +6,8 @@ from migen import * from artiq.gateware.drtio.link_layer import * -def process(dut, seq): +def process(seq): + dut = Scrambler(8) rseq = [] def pump(): yield dut.i.eq(seq[0]) @@ -24,17 +25,11 @@ def process(dut, seq): class TestScrambler(unittest.TestCase): def test_roundtrip(self): seq = list(range(256))*3 - scrambled_seq = process(Scrambler(8), seq) - descrambled_seq = process(Descrambler(8), scrambled_seq) + scrambled_seq = process(seq) + descrambled_seq = process(scrambled_seq) self.assertNotEqual(seq, scrambled_seq) self.assertEqual(seq, descrambled_seq) - def test_resync(self): - seq = list(range(256)) - scrambled_seq = process(Scrambler(8), seq) - descrambled_seq = process(Descrambler(8), scrambled_seq[20:]) - self.assertEqual(seq[100:], descrambled_seq[80:]) - class Loopback(Module): def __init__(self, nwords): @@ -50,12 +45,24 @@ class TestLinkLayer(unittest.TestCase): def test_packets(self): dut = Loopback(4) + def link_init(): + yield dut.tx.link_init.eq(1) + yield + yield + yield dut.tx.link_init.eq(0) + yield + rt_packets = [ [0x12459970, 0x9938cdef, 0x12340000], [0xabcdef00, 0x12345678], [0xeeeeeeee, 0xffffffff, 0x01020304, 0x11223344] ] def transmit_rt_packets(): + while not (yield dut.tx.link_init): + yield + while (yield dut.tx.link_init): + yield + for packet in rt_packets: yield dut.tx.rt_frame.eq(1) for data in packet: @@ -70,6 +77,11 @@ class TestLinkLayer(unittest.TestCase): rx_rt_packets = [] @passive def receive_rt_packets(): + while not (yield dut.tx.link_init): + yield + while (yield dut.tx.link_init): + yield + while True: packet = [] rx_rt_packets.append(packet) @@ -78,7 +90,9 @@ class TestLinkLayer(unittest.TestCase): while (yield dut.rx.rt_frame): packet.append((yield dut.rx.rt_data)) yield - run_simulation(dut, [transmit_rt_packets(), receive_rt_packets()]) + + run_simulation(dut, [link_init(), + transmit_rt_packets(), receive_rt_packets()]) for packet in rx_rt_packets: print(" ".join("{:08x}".format(x) for x in packet))