diff --git a/test/test_ordered_set.py b/test/test_ordered_set.py index a18befd..1fe3b16 100644 --- a/test/test_ordered_set.py +++ b/test/test_ordered_set.py @@ -6,7 +6,7 @@ import unittest from migen import * from usb3_pipe.common import TSEQ, TS1 -from usb3_pipe.ordered_set import OrderedSetReceiver +from usb3_pipe.ordered_set import OrderedSetReceiver, OrderedSetTransmitter class TestOrderedSet(unittest.TestCase): @@ -38,7 +38,7 @@ class TestOrderedSet(unittest.TestCase): generator(dut, n_loops=32), checker(dut, n_loops=32, n_ordered_sets=4), ] - run_simulation(dut, generators, vcd_name="tseq.vcd") + run_simulation(dut, generators) def test_ts1_receiver(self): @@ -72,4 +72,75 @@ class TestOrderedSet(unittest.TestCase): generator(dut, n_loops=32), checker(dut, n_loops=32, n_ordered_sets=4), ] - run_simulation(dut, generators, vcd_name="ts1.vcd") \ No newline at end of file + run_simulation(dut, generators) + + def test_tseq_transmitter(self): + tseq_length = len(TSEQ.to_bytes())//4 + tseq_words = [int.from_bytes(TSEQ.to_bytes()[4*i:4*(i+1)], "little") for i in range(tseq_length)] + def generator(dut, n_loops): + for i in range(n_loops): + yield dut.send.eq(1) + yield + yield dut.send.eq(0) + yield + while not (yield dut.done): + yield + yield + for i in range(128): + yield + dut.run = False + + def checker(dut, n_loops, n_ordered_sets): + words = [] + yield dut.source.ready.eq(1) + yield + while dut.run: + if (yield dut.source.valid): + words.append((yield dut.source.data)) + yield + self.assertEqual(words, tseq_words*n_loops*n_ordered_sets) + + dut = OrderedSetTransmitter(ordered_set=TSEQ, n_ordered_sets=4, data_width=32) + dut.run = True + generators = [ + generator(dut, n_loops=32), + checker(dut, n_loops=32, n_ordered_sets=4), + ] + run_simulation(dut, generators) + + def test_ts1_transmitter(self): + ts1_length = len(TS1.to_bytes())//4 + ts1_words = [int.from_bytes(TS1.to_bytes()[4*i:4*(i+1)], "little") for i in range(ts1_length)] + def generator(dut, n_loops): + for i in range(n_loops): + yield dut.send.eq(1) + yield dut.reset.eq(0) + yield dut.loopback.eq(0) + yield dut.scrambling.eq(1) + yield + yield dut.send.eq(0) + yield + while not (yield dut.done): + yield + yield + for i in range(128): + yield + dut.run = False + + def checker(dut, n_loops, n_ordered_sets): + words = [] + yield dut.source.ready.eq(1) + yield + while dut.run: + if (yield dut.source.valid): + words.append((yield dut.source.data)) + yield + self.assertEqual(words, ts1_words*n_loops*n_ordered_sets) + + dut = OrderedSetTransmitter(ordered_set=TS1, n_ordered_sets=4, data_width=32) + dut.run = True + generators = [ + generator(dut, n_loops=32), + checker(dut, n_loops=32, n_ordered_sets=4), + ] + run_simulation(dut, generators) diff --git a/usb3_pipe/ordered_set.py b/usb3_pipe/ordered_set.py index f304fb9..66608ae 100644 --- a/usb3_pipe/ordered_set.py +++ b/usb3_pipe/ordered_set.py @@ -28,7 +28,7 @@ class OrderedSetReceiver(Module): port = mem.get_port(async_read=True) self.specials += mem, port - # Error detection -------------------------------------------------------------------------- + # Data check ------------------------------------------------------------------------------- error = Signal() error_mask = Signal(data_width, reset=2**data_width-1) if ordered_set.name in ["TS1", "TS2"]: @@ -101,3 +101,86 @@ class OrderedSetReceiver(Module): # Result ----------------------------------------------------------------------------------- self.comb += self.detected.eq(count == (mem_depth*n_ordered_sets - 1)) + +# Ordered Set Transmitter -------------------------------------------------------------------------- + +class OrderedSetTransmitter(Module): + def __init__(self, ordered_set, n_ordered_sets, data_width): + assert data_width in [16, 32] + self.send = Signal() # i + self.done = Signal() # i + self.source = stream.Endpoint([("data", data_width), ("ctrl", data_width//8)]) + + if ordered_set.name in ["TS1", "TS2"]: + self.reset = Signal() # i + self.loopback = Signal() # i + self.scrambling = Signal() # i + + # # # + + run = Signal() + + # Memory -------------------------------------------------------------------------------- + mem_depth = len(ordered_set.to_bytes())//(data_width//8) + mem_init = [int.from_bytes(ordered_set.to_bytes()[4*i:4*(i+1)], "little") for i in range(mem_depth)] + mem = Memory(data_width, mem_depth, mem_init) + port = mem.get_port(async_read=True) + self.specials += mem, port + + # Memory address generation ---------------------------------------------------------------- + self.sync += [ + If(self.source.valid & self.source.ready, + If(port.adr == (mem_depth - 1), + port.adr.eq(0) + ).Else( + port.adr.eq(port.adr + 1) + ) + ).Else( + port.adr.eq(0) + ) + ] + + # Link Config ------------------------------------------------------------------------------ + link_config = Signal(8) + if ordered_set.name in ["TS1", "TS2"]: + self.comb += [ + link_config[0].eq(self.reset), + link_config[1].eq(self.loopback), + link_config[2].eq(~self.scrambling) + ] + + # Data generation -------------------------------------------------------------------------- + if ordered_set.name in ["TS1", "TS2"]: + first_ctrl = 2**(data_width//8) - 1 + else: + first_ctrl = 1 + self.comb += [ + self.source.valid.eq(self.send | ~self.done), + If(port.adr == 0, + self.source.ctrl.eq(first_ctrl), + ).Else( + self.source.ctrl.eq(0) + ), + self.source.data.eq(port.dat_r) + ] + if ordered_set.name in ["TS1", "TS2"]: + if data_width == 32: + self.comb += If(port.adr == 1, self.source.data[8:16].eq(link_config)) + else: + self.comb += If(port.adr == 2, self.source.data[8:16].eq(link_config)) + + # Count ------------------------------------------------------------------------------------ + count = Signal(max=mem_depth*n_ordered_sets) + self.sync += [ + If(self.send, + run.eq(1), + count.eq(0), + ).Elif(self.done, + run.eq(0), + ).Else( + count.eq(count + 1) + ) + ] + + # Result ----------------------------------------------------------------------------------- + self.comb += self.done.eq(count == (mem_depth*n_ordered_sets - 1))