From 28686fb11544147bd813be36ea1223cc92089f44 Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Tue, 18 May 2021 22:05:44 -0700 Subject: [PATCH 01/14] Update readme --- README.md | 80 +++++++++++++++++++++++++++---------------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index e37a26355..408e40f2b 100644 --- a/README.md +++ b/README.md @@ -14,14 +14,14 @@ utilize [cocotbext-axi](https://github.com/alexforencich/cocotbext-axi). ## Documentation -### arbiter module +### `arbiter` module General-purpose parametrizable arbiter. Supports priority and round-robin arbitration. Supports blocking until request release or acknowledge. -### axis_adapter module +### `axis_adapter` module -The axis_adapter module bridges AXI stream busses of differing widths. The +The `axis_adapter` module bridges AXI stream buses of differing widths. The module is parametrizable, but there are certain restrictions. First, the bus word widths must be identical (e.g. one 8-bit lane and eight 8-bit lanes, but not one 16-bit lane and one 32-bit lane). Second, the bus widths must be @@ -29,80 +29,80 @@ related by an integer multiple (e.g. 2 words and 6 words, but not 4 words and 6 words). Wait states will be inserted on the wider bus side when necessary. -### axis_arb_mux module +### `axis_arb_mux` module -Frame-aware AXI stream arbitrated muliplexer with parametrizable data width +Frame-aware AXI stream arbitrated multiplexer with parametrizable data width and port count. Supports priority and round-robin arbitration. -Wrappers can generated with axis_arb_mux_wrap.py. +Wrappers can generated with `axis_arb_mux_wrap.py`. -### axis_async_fifo module +### `axis_async_fifo` module Configurable word-based or frame-based asynchronous FIFO with parametrizable data width, depth, type, and bad frame detection. Supports power of two depths only. -### axis_async_fifo_adapter module +### `axis_async_fifo_adapter` module Configurable word-based or frame-based asynchronous FIFO with parametrizable data width, depth, type, and bad frame detection. Supports different input and output data widths, inserting an axis_adapter instance appropriately. Supports power of two depths only. -### axis_broadcast module +### `axis_broadcast` module AXI stream broadcaster. Duplicates one input stream across multiple output streams. -### axis_cobs_decode +### `axis_cobs_decode` Consistent Overhead Byte Stuffing (COBS) decoder. Fixed 8 bit width. -### axis_cobs_encode +### `axis_cobs_encode` Consistent Overhead Byte Stuffing (COBS) encoder. Fixed 8 bit width. Configurable zero insertion. -### axis_crosspoint module +### `axis_crosspoint` module -Basic crosspoint switch. tready signal not supported. Parametrizable data +Basic crosspoint switch. `tready` signal not supported. Parametrizable data width. -Wrappers can generated with axis_crosspoint_wrap.py. +Wrappers can generated with `axis_crosspoint_wrap.py`. -### axis_demux module +### `axis_demux` module -Frame-aware AXI stream demuliplexer with parametrizable data width and port +Frame-aware AXI stream demultiplexer with parametrizable data width and port count. -### axis_fifo module +### `axis_fifo` module Configurable word-based or frame-based synchronous FIFO with parametrizable data width, depth, type, and bad frame detection. Supports power of two depths only. -### axis_fifo_adapter module +### `axis_fifo_adapter` module Configurable word-based or frame-based synchronous FIFO with parametrizable data width, depth, type, and bad frame detection. Supports different input and output data widths, inserting an axis_adapter instance appropriately. Supports power of two depths only. -### axis_frame_join module +### `axis_frame_join` module Frame joiner with optional tag and parametrizable port count. 8 bit data path only. -Wrappers can generated with axis_frame_join_wrap.py. +Wrappers can generated with `axis_frame_join_wrap.py`. -### axis_frame_length_adjust module +### `axis_frame_length_adjust` module Frame length adjuster module. Truncates or pads frames as necessary to meet the specified minimum and maximum length. Reports the original and current lengths as well as whether the packet was truncated or padded. Length limits are configurable at run time. -### axis_frame_length_adjust_fifo module +### `axis_frame_length_adjust_fifo` module Frame length adjuster module with FIFO. Truncates or pads frames as necessary to meet the specified minimum and maximum length. Reports the original and @@ -110,75 +110,75 @@ current lengths as well as whether the packet was truncated or padded. FIFOs are used so that the status information can be read before the packet itself. Length limits are configurable at run time. -### axis_ll_bridge module +### `axis_ll_bridge` module AXI stream to LocalLink bridge. -### axis_mux module +### `axis_mux` module -Frame-aware AXI stream muliplexer with parametrizable data width and port +Frame-aware AXI stream multiplexer with parametrizable data width and port count. -Wrappers can generated with axis_mux_wrap.py. +Wrappers can generated with `axis_mux_wrap.py`. -### axis_pipeline_register module +### `axis_pipeline_register` module Parametrizable register pipeline. LENGTH parameter determines number of register stages. -### axis_ram_switch module +### `axis_ram_switch` module Frame-aware AXI stream RAM switch with parametrizable data width, port count, and FIFO size. Uses block RAM for storing packets in transit, time-sharing the RAM interface between ports. Functionally equivalent to a combination of per-port frame FIFOs and width converters connected to an AXI stream switch. -### axis_rate_limit module +### `axis_rate_limit` module Fractional rate limiter, supports word and frame modes. Inserts wait states to limit data rate to specified ratio. Frame mode inserts wait states at end of frames, word mode ignores frames and inserts wait states at any point. Parametrizable data width. Rate and mode are configurable at run time. -### axis_register module +### `axis_register` module Datapath register with parameter to select between skid buffer, simple buffer, and bypass. Use to improve timing for long routes. -### axis_srl_fifo module +### `axis_srl_fifo` module SRL-based FIFO. Good for small FIFOs. SRLs on Xilinx FPGAs have a very fast input setup time, so this module can be used to aid in timing closure. -### axis_srl_register module +### `axis_srl_register` module SRL-based register. SRLs on Xilinx FPGAs have a very fast input setup time, so this module can be used to aid in timing closure. -### axis_stat_counter module +### `axis_stat_counter` module Statistics counter module. Counts bytes and frames passing through monitored AXI stream interface. Trigger signal used to reset and dump counts out of AXI -interface, along with tag value. Use with axis_frame_join_N to form a single +interface, along with tag value. Use with `axis_frame_join` to form a single monolithic frame from multiple monitored points with the same trigger. -### axis_switch module +### `axis_switch` module Frame-aware AXI stream switch with parametrizable data width and port count. -Wrappers can generated with axis_switch_wrap.py. +Wrappers can generated with `axis_switch_wrap.py`. -### axis_tap module +### `axis_tap` module AXI stream tap module. Used to make a copy of an AXI stream bus without affecting the bus. Back-pressure on the output results in truncated frames -with tuser set. +with `tuser` set. -### ll_axis_bridge module +### `ll_axis_bridge` module LocalLink to AXI stream bridge. -### priority_encoder module +### `priority_encoder` module Parametrizable priority encoder. From a7ebfdcebb693e514bf6d37e3e4525cb6bcfb003 Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Tue, 25 May 2021 00:13:32 -0700 Subject: [PATCH 02/14] Add arbitration test --- tb/axis_arb_mux/test_axis_arb_mux.py | 56 +++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/tb/axis_arb_mux/test_axis_arb_mux.py b/tb/axis_arb_mux/test_axis_arb_mux.py index fbf8385f6..24b7d4a5e 100644 --- a/tb/axis_arb_mux/test_axis_arb_mux.py +++ b/tb/axis_arb_mux/test_axis_arb_mux.py @@ -33,7 +33,7 @@ import cocotb from cocotb.clock import Clock -from cocotb.triggers import RisingEdge +from cocotb.triggers import RisingEdge, Event from cocotb.regression import TestFactory from cocotbext.axi import AxiStreamBus, AxiStreamFrame, AxiStreamSource, AxiStreamSink @@ -113,6 +113,56 @@ async def run_test(dut, payload_lengths=None, payload_data=None, idle_inserter=N await RisingEdge(dut.clk) +async def run_arb_test(dut): + + tb = TB(dut) + + byte_lanes = tb.source[0].byte_lanes + id_count = 2**len(tb.source[0].bus.tid) + + cur_id = 1 + + await tb.reset() + + test_frames = [] + + length = byte_lanes*16 + test_data = bytearray(itertools.islice(itertools.cycle(range(256)), length)) + + for k in range(5): + test_frame = AxiStreamFrame(test_data, tx_complete=Event()) + test_frame.tid = cur_id + + if k == 0: + test_frame.tdest = 0 + elif k == 4: + await test_frames[1].tx_complete.wait() + for j in range(8): + await RisingEdge(dut.clk) + test_frame.tdest = 0 + else: + test_frame.tdest = 1 + + test_frames.append(test_frame) + await tb.source[test_frame.tdest].send(test_frame) + + cur_id = (cur_id + 1) % id_count + + for k in [0, 1, 2, 4, 3]: + test_frame = test_frames[k] + rx_frame = await tb.sink.recv() + + assert rx_frame.tdata == test_frame.tdata + assert rx_frame.tid == test_frame.tid + assert rx_frame.tdest == test_frame.tdest + assert not rx_frame.tuser + + assert tb.sink.empty() + + await RisingEdge(dut.clk) + await RisingEdge(dut.clk) + + def cycle_pause(): return itertools.cycle([1, 1, 1, 0]) @@ -139,6 +189,10 @@ def incrementing_payload(length): factory.add_option("port", list(range(ports))) factory.generate_tests() + if ports > 1: + factory = TestFactory(run_arb_test) + factory.generate_tests() + # cocotb-test From a7905ed681665fa0300c30e735990ec86a8eb4f0 Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Tue, 25 May 2021 00:31:20 -0700 Subject: [PATCH 03/14] Add stress tests --- tb/axis_adapter/test_axis_adapter.py | 48 +++++++++++++++ tb/axis_arb_mux/test_axis_arb_mux.py | 58 +++++++++++++++++++ tb/axis_async_fifo/test_axis_async_fifo.py | 48 +++++++++++++++ .../test_axis_async_fifo_adapter.py | 48 +++++++++++++++ tb/axis_fifo/test_axis_fifo.py | 48 +++++++++++++++ .../test_axis_fifo_adapter.py | 48 +++++++++++++++ .../test_axis_pipeline_register.py | 48 +++++++++++++++ tb/axis_register/test_axis_register.py | 48 +++++++++++++++ tb/axis_srl_fifo/test_axis_srl_fifo.py | 48 +++++++++++++++ .../test_axis_srl_register.py | 48 +++++++++++++++ 10 files changed, 490 insertions(+) diff --git a/tb/axis_adapter/test_axis_adapter.py b/tb/axis_adapter/test_axis_adapter.py index 39df48baf..d9c0e148e 100644 --- a/tb/axis_adapter/test_axis_adapter.py +++ b/tb/axis_adapter/test_axis_adapter.py @@ -26,6 +26,7 @@ import itertools import logging import os +import random import cocotb_test.simulator import pytest @@ -109,6 +110,48 @@ async def run_test(dut, payload_lengths=None, payload_data=None, idle_inserter=N await RisingEdge(dut.clk) +async def run_stress_test(dut, idle_inserter=None, backpressure_inserter=None): + + tb = TB(dut) + + byte_lanes = max(tb.source.byte_lanes, tb.sink.byte_lanes) + id_count = 2**len(tb.source.bus.tid) + + cur_id = 1 + + await tb.reset() + + tb.set_idle_generator(idle_inserter) + tb.set_backpressure_generator(backpressure_inserter) + + test_frames = [] + + for k in range(128): + length = random.randint(1, byte_lanes*16) + test_data = bytearray(itertools.islice(itertools.cycle(range(256)), length)) + test_frame = AxiStreamFrame(test_data) + test_frame.tid = cur_id + test_frame.tdest = cur_id + + test_frames.append(test_frame) + await tb.source.send(test_frame) + + cur_id = (cur_id + 1) % id_count + + for test_frame in test_frames: + rx_frame = await tb.sink.recv() + + assert rx_frame.tdata == test_frame.tdata + assert rx_frame.tid == test_frame.tid + assert rx_frame.tdest == test_frame.tdest + assert not rx_frame.tuser + + assert tb.sink.empty() + + await RisingEdge(dut.clk) + await RisingEdge(dut.clk) + + def cycle_pause(): return itertools.cycle([1, 1, 1, 0]) @@ -132,6 +175,11 @@ def incrementing_payload(length): factory.add_option("backpressure_inserter", [None, cycle_pause]) factory.generate_tests() + factory = TestFactory(run_stress_test) + factory.add_option("idle_inserter", [None, cycle_pause]) + factory.add_option("backpressure_inserter", [None, cycle_pause]) + factory.generate_tests() + # cocotb-test diff --git a/tb/axis_arb_mux/test_axis_arb_mux.py b/tb/axis_arb_mux/test_axis_arb_mux.py index 24b7d4a5e..ac07e5aef 100644 --- a/tb/axis_arb_mux/test_axis_arb_mux.py +++ b/tb/axis_arb_mux/test_axis_arb_mux.py @@ -26,6 +26,7 @@ import itertools import logging import os +import random import subprocess import cocotb_test.simulator @@ -163,6 +164,58 @@ async def run_arb_test(dut): await RisingEdge(dut.clk) +async def run_stress_test(dut, idle_inserter=None, backpressure_inserter=None): + + tb = TB(dut) + + byte_lanes = tb.source[0].byte_lanes + id_count = 2**len(tb.source[0].bus.tid) + + cur_id = 1 + + await tb.reset() + + tb.set_idle_generator(idle_inserter) + tb.set_backpressure_generator(backpressure_inserter) + + test_frames = [list() for x in tb.source] + + for p in range(len(tb.source)): + for k in range(128): + length = random.randint(1, byte_lanes*16) + test_data = bytearray(itertools.islice(itertools.cycle(range(256)), length)) + test_frame = AxiStreamFrame(test_data) + test_frame.tid = p + test_frame.tdest = cur_id + + test_frames[p].append(test_frame) + await tb.source[p].send(test_frame) + + cur_id = (cur_id + 1) % id_count + + while any(test_frames): + rx_frame = await tb.sink.recv() + + test_frame = None + + for lst in test_frames: + if lst and lst[0].tid == rx_frame.tid: + test_frame = lst.pop(0) + break + + assert test_frame is not None + + assert rx_frame.tdata == test_frame.tdata + assert rx_frame.tid == test_frame.tid + assert rx_frame.tdest == test_frame.tdest + assert not rx_frame.tuser + + assert tb.sink.empty() + + await RisingEdge(dut.clk) + await RisingEdge(dut.clk) + + def cycle_pause(): return itertools.cycle([1, 1, 1, 0]) @@ -193,6 +246,11 @@ def incrementing_payload(length): factory = TestFactory(run_arb_test) factory.generate_tests() + factory = TestFactory(run_stress_test) + factory.add_option("idle_inserter", [None, cycle_pause]) + factory.add_option("backpressure_inserter", [None, cycle_pause]) + factory.generate_tests() + # cocotb-test diff --git a/tb/axis_async_fifo/test_axis_async_fifo.py b/tb/axis_async_fifo/test_axis_async_fifo.py index f5eea3afd..b3693ca3d 100644 --- a/tb/axis_async_fifo/test_axis_async_fifo.py +++ b/tb/axis_async_fifo/test_axis_async_fifo.py @@ -26,6 +26,7 @@ import itertools import logging import os +import random import cocotb_test.simulator import pytest @@ -225,6 +226,48 @@ async def run_test_overflow(dut): await RisingEdge(dut.s_clk) +async def run_stress_test(dut, idle_inserter=None, backpressure_inserter=None): + + tb = TB(dut) + + byte_lanes = tb.source.byte_lanes + id_count = 2**len(tb.source.bus.tid) + + cur_id = 1 + + await tb.reset() + + tb.set_idle_generator(idle_inserter) + tb.set_backpressure_generator(backpressure_inserter) + + test_frames = [] + + for k in range(128): + length = random.randint(1, byte_lanes*16) + test_data = bytearray(itertools.islice(itertools.cycle(range(256)), length)) + test_frame = AxiStreamFrame(test_data) + test_frame.tid = cur_id + test_frame.tdest = cur_id + + test_frames.append(test_frame) + await tb.source.send(test_frame) + + cur_id = (cur_id + 1) % id_count + + for test_frame in test_frames: + rx_frame = await tb.sink.recv() + + assert rx_frame.tdata == test_frame.tdata + assert rx_frame.tid == test_frame.tid + assert rx_frame.tdest == test_frame.tdest + assert not rx_frame.tuser + + assert tb.sink.empty() + + await RisingEdge(dut.s_clk) + await RisingEdge(dut.s_clk) + + def cycle_pause(): return itertools.cycle([1, 1, 1, 0]) @@ -252,6 +295,11 @@ def incrementing_payload(length): factory = TestFactory(test) factory.generate_tests() + factory = TestFactory(run_stress_test) + factory.add_option("idle_inserter", [None, cycle_pause]) + factory.add_option("backpressure_inserter", [None, cycle_pause]) + factory.generate_tests() + # cocotb-test diff --git a/tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py b/tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py index c2a4761e6..5bcef7600 100644 --- a/tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py +++ b/tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py @@ -26,6 +26,7 @@ import itertools import logging import os +import random import cocotb_test.simulator import pytest @@ -228,6 +229,48 @@ async def run_test_overflow(dut): await RisingEdge(dut.s_clk) +async def run_stress_test(dut, idle_inserter=None, backpressure_inserter=None): + + tb = TB(dut) + + byte_lanes = max(tb.source.byte_lanes, tb.sink.byte_lanes) + id_count = 2**len(tb.source.bus.tid) + + cur_id = 1 + + await tb.reset() + + tb.set_idle_generator(idle_inserter) + tb.set_backpressure_generator(backpressure_inserter) + + test_frames = [] + + for k in range(128): + length = random.randint(1, byte_lanes*16) + test_data = bytearray(itertools.islice(itertools.cycle(range(256)), length)) + test_frame = AxiStreamFrame(test_data) + test_frame.tid = cur_id + test_frame.tdest = cur_id + + test_frames.append(test_frame) + await tb.source.send(test_frame) + + cur_id = (cur_id + 1) % id_count + + for test_frame in test_frames: + rx_frame = await tb.sink.recv() + + assert rx_frame.tdata == test_frame.tdata + assert rx_frame.tid == test_frame.tid + assert rx_frame.tdest == test_frame.tdest + assert not rx_frame.tuser + + assert tb.sink.empty() + + await RisingEdge(dut.s_clk) + await RisingEdge(dut.s_clk) + + def cycle_pause(): return itertools.cycle([1, 1, 1, 0]) @@ -255,6 +298,11 @@ def incrementing_payload(length): factory = TestFactory(test) factory.generate_tests() + factory = TestFactory(run_stress_test) + factory.add_option("idle_inserter", [None, cycle_pause]) + factory.add_option("backpressure_inserter", [None, cycle_pause]) + factory.generate_tests() + # cocotb-test diff --git a/tb/axis_fifo/test_axis_fifo.py b/tb/axis_fifo/test_axis_fifo.py index 0cf880dcb..7eb5ff240 100644 --- a/tb/axis_fifo/test_axis_fifo.py +++ b/tb/axis_fifo/test_axis_fifo.py @@ -26,6 +26,7 @@ import itertools import logging import os +import random import cocotb_test.simulator import pytest @@ -224,6 +225,48 @@ async def run_test_overflow(dut): await RisingEdge(dut.clk) +async def run_stress_test(dut, idle_inserter=None, backpressure_inserter=None): + + tb = TB(dut) + + byte_lanes = tb.source.byte_lanes + id_count = 2**len(tb.source.bus.tid) + + cur_id = 1 + + await tb.reset() + + tb.set_idle_generator(idle_inserter) + tb.set_backpressure_generator(backpressure_inserter) + + test_frames = [] + + for k in range(128): + length = random.randint(1, byte_lanes*16) + test_data = bytearray(itertools.islice(itertools.cycle(range(256)), length)) + test_frame = AxiStreamFrame(test_data) + test_frame.tid = cur_id + test_frame.tdest = cur_id + + test_frames.append(test_frame) + await tb.source.send(test_frame) + + cur_id = (cur_id + 1) % id_count + + for test_frame in test_frames: + rx_frame = await tb.sink.recv() + + assert rx_frame.tdata == test_frame.tdata + assert rx_frame.tid == test_frame.tid + assert rx_frame.tdest == test_frame.tdest + assert not rx_frame.tuser + + assert tb.sink.empty() + + await RisingEdge(dut.clk) + await RisingEdge(dut.clk) + + def cycle_pause(): return itertools.cycle([1, 1, 1, 0]) @@ -251,6 +294,11 @@ def incrementing_payload(length): factory = TestFactory(test) factory.generate_tests() + factory = TestFactory(run_stress_test) + factory.add_option("idle_inserter", [None, cycle_pause]) + factory.add_option("backpressure_inserter", [None, cycle_pause]) + factory.generate_tests() + # cocotb-test diff --git a/tb/axis_fifo_adapter/test_axis_fifo_adapter.py b/tb/axis_fifo_adapter/test_axis_fifo_adapter.py index d6f91ac5c..2a5c56214 100644 --- a/tb/axis_fifo_adapter/test_axis_fifo_adapter.py +++ b/tb/axis_fifo_adapter/test_axis_fifo_adapter.py @@ -26,6 +26,7 @@ import itertools import logging import os +import random import cocotb_test.simulator import pytest @@ -224,6 +225,48 @@ async def run_test_overflow(dut): await RisingEdge(dut.clk) +async def run_stress_test(dut, idle_inserter=None, backpressure_inserter=None): + + tb = TB(dut) + + byte_lanes = max(tb.source.byte_lanes, tb.sink.byte_lanes) + id_count = 2**len(tb.source.bus.tid) + + cur_id = 1 + + await tb.reset() + + tb.set_idle_generator(idle_inserter) + tb.set_backpressure_generator(backpressure_inserter) + + test_frames = [] + + for k in range(128): + length = random.randint(1, byte_lanes*16) + test_data = bytearray(itertools.islice(itertools.cycle(range(256)), length)) + test_frame = AxiStreamFrame(test_data) + test_frame.tid = cur_id + test_frame.tdest = cur_id + + test_frames.append(test_frame) + await tb.source.send(test_frame) + + cur_id = (cur_id + 1) % id_count + + for test_frame in test_frames: + rx_frame = await tb.sink.recv() + + assert rx_frame.tdata == test_frame.tdata + assert rx_frame.tid == test_frame.tid + assert rx_frame.tdest == test_frame.tdest + assert not rx_frame.tuser + + assert tb.sink.empty() + + await RisingEdge(dut.clk) + await RisingEdge(dut.clk) + + def cycle_pause(): return itertools.cycle([1, 1, 1, 0]) @@ -251,6 +294,11 @@ def incrementing_payload(length): factory = TestFactory(test) factory.generate_tests() + factory = TestFactory(run_stress_test) + factory.add_option("idle_inserter", [None, cycle_pause]) + factory.add_option("backpressure_inserter", [None, cycle_pause]) + factory.generate_tests() + # cocotb-test diff --git a/tb/axis_pipeline_register/test_axis_pipeline_register.py b/tb/axis_pipeline_register/test_axis_pipeline_register.py index 7a0f86809..fb9318217 100644 --- a/tb/axis_pipeline_register/test_axis_pipeline_register.py +++ b/tb/axis_pipeline_register/test_axis_pipeline_register.py @@ -26,6 +26,7 @@ import itertools import logging import os +import random import cocotb_test.simulator import pytest @@ -109,6 +110,48 @@ async def run_test(dut, payload_lengths=None, payload_data=None, idle_inserter=N await RisingEdge(dut.clk) +async def run_stress_test(dut, idle_inserter=None, backpressure_inserter=None): + + tb = TB(dut) + + byte_lanes = tb.source.byte_lanes + id_count = 2**len(tb.source.bus.tid) + + cur_id = 1 + + await tb.reset() + + tb.set_idle_generator(idle_inserter) + tb.set_backpressure_generator(backpressure_inserter) + + test_frames = [] + + for k in range(128): + length = random.randint(1, byte_lanes*16) + test_data = bytearray(itertools.islice(itertools.cycle(range(256)), length)) + test_frame = AxiStreamFrame(test_data) + test_frame.tid = cur_id + test_frame.tdest = cur_id + + test_frames.append(test_frame) + await tb.source.send(test_frame) + + cur_id = (cur_id + 1) % id_count + + for test_frame in test_frames: + rx_frame = await tb.sink.recv() + + assert rx_frame.tdata == test_frame.tdata + assert rx_frame.tid == test_frame.tid + assert rx_frame.tdest == test_frame.tdest + assert not rx_frame.tuser + + assert tb.sink.empty() + + await RisingEdge(dut.clk) + await RisingEdge(dut.clk) + + def cycle_pause(): return itertools.cycle([1, 1, 1, 0]) @@ -132,6 +175,11 @@ def incrementing_payload(length): factory.add_option("backpressure_inserter", [None, cycle_pause]) factory.generate_tests() + factory = TestFactory(run_stress_test) + factory.add_option("idle_inserter", [None, cycle_pause]) + factory.add_option("backpressure_inserter", [None, cycle_pause]) + factory.generate_tests() + # cocotb-test diff --git a/tb/axis_register/test_axis_register.py b/tb/axis_register/test_axis_register.py index 26b11fe88..970630338 100644 --- a/tb/axis_register/test_axis_register.py +++ b/tb/axis_register/test_axis_register.py @@ -26,6 +26,7 @@ import itertools import logging import os +import random import cocotb_test.simulator import pytest @@ -109,6 +110,48 @@ async def run_test(dut, payload_lengths=None, payload_data=None, idle_inserter=N await RisingEdge(dut.clk) +async def run_stress_test(dut, idle_inserter=None, backpressure_inserter=None): + + tb = TB(dut) + + byte_lanes = tb.source.byte_lanes + id_count = 2**len(tb.source.bus.tid) + + cur_id = 1 + + await tb.reset() + + tb.set_idle_generator(idle_inserter) + tb.set_backpressure_generator(backpressure_inserter) + + test_frames = [] + + for k in range(128): + length = random.randint(1, byte_lanes*16) + test_data = bytearray(itertools.islice(itertools.cycle(range(256)), length)) + test_frame = AxiStreamFrame(test_data) + test_frame.tid = cur_id + test_frame.tdest = cur_id + + test_frames.append(test_frame) + await tb.source.send(test_frame) + + cur_id = (cur_id + 1) % id_count + + for test_frame in test_frames: + rx_frame = await tb.sink.recv() + + assert rx_frame.tdata == test_frame.tdata + assert rx_frame.tid == test_frame.tid + assert rx_frame.tdest == test_frame.tdest + assert not rx_frame.tuser + + assert tb.sink.empty() + + await RisingEdge(dut.clk) + await RisingEdge(dut.clk) + + def cycle_pause(): return itertools.cycle([1, 1, 1, 0]) @@ -132,6 +175,11 @@ def incrementing_payload(length): factory.add_option("backpressure_inserter", [None, cycle_pause]) factory.generate_tests() + factory = TestFactory(run_stress_test) + factory.add_option("idle_inserter", [None, cycle_pause]) + factory.add_option("backpressure_inserter", [None, cycle_pause]) + factory.generate_tests() + # cocotb-test diff --git a/tb/axis_srl_fifo/test_axis_srl_fifo.py b/tb/axis_srl_fifo/test_axis_srl_fifo.py index 73b16678b..8bdc70671 100644 --- a/tb/axis_srl_fifo/test_axis_srl_fifo.py +++ b/tb/axis_srl_fifo/test_axis_srl_fifo.py @@ -26,6 +26,7 @@ import itertools import logging import os +import random import cocotb_test.simulator import pytest @@ -214,6 +215,48 @@ async def run_test_overflow(dut): await RisingEdge(dut.clk) +async def run_stress_test(dut, idle_inserter=None, backpressure_inserter=None): + + tb = TB(dut) + + byte_lanes = tb.source.byte_lanes + id_count = 2**len(tb.source.bus.tid) + + cur_id = 1 + + await tb.reset() + + tb.set_idle_generator(idle_inserter) + tb.set_backpressure_generator(backpressure_inserter) + + test_frames = [] + + for k in range(128): + length = random.randint(1, byte_lanes*16) + test_data = bytearray(itertools.islice(itertools.cycle(range(256)), length)) + test_frame = AxiStreamFrame(test_data) + test_frame.tid = cur_id + test_frame.tdest = cur_id + + test_frames.append(test_frame) + await tb.source.send(test_frame) + + cur_id = (cur_id + 1) % id_count + + for test_frame in test_frames: + rx_frame = await tb.sink.recv() + + assert rx_frame.tdata == test_frame.tdata + assert rx_frame.tid == test_frame.tid + assert rx_frame.tdest == test_frame.tdest + assert not rx_frame.tuser + + assert tb.sink.empty() + + await RisingEdge(dut.clk) + await RisingEdge(dut.clk) + + def cycle_pause(): return itertools.cycle([1, 1, 1, 0]) @@ -241,6 +284,11 @@ def incrementing_payload(length): factory = TestFactory(test) factory.generate_tests() + factory = TestFactory(run_stress_test) + factory.add_option("idle_inserter", [None, cycle_pause]) + factory.add_option("backpressure_inserter", [None, cycle_pause]) + factory.generate_tests() + # cocotb-test diff --git a/tb/axis_srl_register/test_axis_srl_register.py b/tb/axis_srl_register/test_axis_srl_register.py index 9f298d679..71c2f1605 100644 --- a/tb/axis_srl_register/test_axis_srl_register.py +++ b/tb/axis_srl_register/test_axis_srl_register.py @@ -26,6 +26,7 @@ import itertools import logging import os +import random import cocotb_test.simulator import pytest @@ -109,6 +110,48 @@ async def run_test(dut, payload_lengths=None, payload_data=None, idle_inserter=N await RisingEdge(dut.clk) +async def run_stress_test(dut, idle_inserter=None, backpressure_inserter=None): + + tb = TB(dut) + + byte_lanes = tb.source.byte_lanes + id_count = 2**len(tb.source.bus.tid) + + cur_id = 1 + + await tb.reset() + + tb.set_idle_generator(idle_inserter) + tb.set_backpressure_generator(backpressure_inserter) + + test_frames = [] + + for k in range(128): + length = random.randint(1, byte_lanes*16) + test_data = bytearray(itertools.islice(itertools.cycle(range(256)), length)) + test_frame = AxiStreamFrame(test_data) + test_frame.tid = cur_id + test_frame.tdest = cur_id + + test_frames.append(test_frame) + await tb.source.send(test_frame) + + cur_id = (cur_id + 1) % id_count + + for test_frame in test_frames: + rx_frame = await tb.sink.recv() + + assert rx_frame.tdata == test_frame.tdata + assert rx_frame.tid == test_frame.tid + assert rx_frame.tdest == test_frame.tdest + assert not rx_frame.tuser + + assert tb.sink.empty() + + await RisingEdge(dut.clk) + await RisingEdge(dut.clk) + + def cycle_pause(): return itertools.cycle([1, 1, 1, 0]) @@ -132,6 +175,11 @@ def incrementing_payload(length): factory.add_option("backpressure_inserter", [None, cycle_pause]) factory.generate_tests() + factory = TestFactory(run_stress_test) + factory.add_option("idle_inserter", [None, cycle_pause]) + factory.add_option("backpressure_inserter", [None, cycle_pause]) + factory.generate_tests() + # cocotb-test From c1bfa8cc418266a59785795c489ec0dfa12f4e2d Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Tue, 25 May 2021 00:55:59 -0700 Subject: [PATCH 04/14] Add tuser assert tests --- tb/axis_adapter/test_axis_adapter.py | 25 ++++++++++++++++ tb/axis_arb_mux/test_axis_arb_mux.py | 26 +++++++++++++++++ tb/axis_mux/test_axis_mux.py | 29 +++++++++++++++++++ .../test_axis_pipeline_register.py | 25 ++++++++++++++++ tb/axis_register/test_axis_register.py | 25 ++++++++++++++++ .../test_axis_srl_register.py | 25 ++++++++++++++++ 6 files changed, 155 insertions(+) diff --git a/tb/axis_adapter/test_axis_adapter.py b/tb/axis_adapter/test_axis_adapter.py index d9c0e148e..2b34c591e 100644 --- a/tb/axis_adapter/test_axis_adapter.py +++ b/tb/axis_adapter/test_axis_adapter.py @@ -110,6 +110,27 @@ async def run_test(dut, payload_lengths=None, payload_data=None, idle_inserter=N await RisingEdge(dut.clk) +async def run_test_tuser_assert(dut): + + tb = TB(dut) + + await tb.reset() + + test_data = bytearray(itertools.islice(itertools.cycle(range(256)), 32)) + test_frame = AxiStreamFrame(test_data, tuser=1) + await tb.source.send(test_frame) + + rx_frame = await tb.sink.recv() + + assert rx_frame.tdata == test_data + assert rx_frame.tuser + + assert tb.sink.empty() + + await RisingEdge(dut.clk) + await RisingEdge(dut.clk) + + async def run_stress_test(dut, idle_inserter=None, backpressure_inserter=None): tb = TB(dut) @@ -175,6 +196,10 @@ def incrementing_payload(length): factory.add_option("backpressure_inserter", [None, cycle_pause]) factory.generate_tests() + for test in [run_test_tuser_assert]: + factory = TestFactory(test) + factory.generate_tests() + factory = TestFactory(run_stress_test) factory.add_option("idle_inserter", [None, cycle_pause]) factory.add_option("backpressure_inserter", [None, cycle_pause]) diff --git a/tb/axis_arb_mux/test_axis_arb_mux.py b/tb/axis_arb_mux/test_axis_arb_mux.py index ac07e5aef..0aa3426a9 100644 --- a/tb/axis_arb_mux/test_axis_arb_mux.py +++ b/tb/axis_arb_mux/test_axis_arb_mux.py @@ -114,6 +114,27 @@ async def run_test(dut, payload_lengths=None, payload_data=None, idle_inserter=N await RisingEdge(dut.clk) +async def run_test_tuser_assert(dut, port=0): + + tb = TB(dut) + + await tb.reset() + + test_data = bytearray(itertools.islice(itertools.cycle(range(256)), 32)) + test_frame = AxiStreamFrame(test_data, tuser=1) + await tb.source[port].send(test_frame) + + rx_frame = await tb.sink.recv() + + assert rx_frame.tdata == test_data + assert rx_frame.tuser + + assert tb.sink.empty() + + await RisingEdge(dut.clk) + await RisingEdge(dut.clk) + + async def run_arb_test(dut): tb = TB(dut) @@ -242,6 +263,11 @@ def incrementing_payload(length): factory.add_option("port", list(range(ports))) factory.generate_tests() + for test in [run_test_tuser_assert]: + factory = TestFactory(test) + factory.add_option("port", list(range(ports))) + factory.generate_tests() + if ports > 1: factory = TestFactory(run_arb_test) factory.generate_tests() diff --git a/tb/axis_mux/test_axis_mux.py b/tb/axis_mux/test_axis_mux.py index fb9a26d52..777d95f8f 100644 --- a/tb/axis_mux/test_axis_mux.py +++ b/tb/axis_mux/test_axis_mux.py @@ -119,6 +119,30 @@ async def run_test(dut, payload_lengths=None, payload_data=None, idle_inserter=N await RisingEdge(dut.clk) +async def run_test_tuser_assert(dut, port=0): + + tb = TB(dut) + + await tb.reset() + + dut.enable.setimmediatevalue(1) + dut.select.setimmediatevalue(port) + + test_data = bytearray(itertools.islice(itertools.cycle(range(256)), 32)) + test_frame = AxiStreamFrame(test_data, tuser=1) + await tb.source[port].send(test_frame) + + rx_frame = await tb.sink.recv() + + assert rx_frame.tdata == test_data + assert rx_frame.tuser + + assert tb.sink.empty() + + await RisingEdge(dut.clk) + await RisingEdge(dut.clk) + + def cycle_pause(): return itertools.cycle([1, 1, 1, 0]) @@ -145,6 +169,11 @@ def incrementing_payload(length): factory.add_option("port", list(range(ports))) factory.generate_tests() + for test in [run_test_tuser_assert]: + factory = TestFactory(test) + factory.add_option("port", list(range(ports))) + factory.generate_tests() + # cocotb-test diff --git a/tb/axis_pipeline_register/test_axis_pipeline_register.py b/tb/axis_pipeline_register/test_axis_pipeline_register.py index fb9318217..482ee5618 100644 --- a/tb/axis_pipeline_register/test_axis_pipeline_register.py +++ b/tb/axis_pipeline_register/test_axis_pipeline_register.py @@ -110,6 +110,27 @@ async def run_test(dut, payload_lengths=None, payload_data=None, idle_inserter=N await RisingEdge(dut.clk) +async def run_test_tuser_assert(dut): + + tb = TB(dut) + + await tb.reset() + + test_data = bytearray(itertools.islice(itertools.cycle(range(256)), 32)) + test_frame = AxiStreamFrame(test_data, tuser=1) + await tb.source.send(test_frame) + + rx_frame = await tb.sink.recv() + + assert rx_frame.tdata == test_data + assert rx_frame.tuser + + assert tb.sink.empty() + + await RisingEdge(dut.clk) + await RisingEdge(dut.clk) + + async def run_stress_test(dut, idle_inserter=None, backpressure_inserter=None): tb = TB(dut) @@ -175,6 +196,10 @@ def incrementing_payload(length): factory.add_option("backpressure_inserter", [None, cycle_pause]) factory.generate_tests() + for test in [run_test_tuser_assert]: + factory = TestFactory(test) + factory.generate_tests() + factory = TestFactory(run_stress_test) factory.add_option("idle_inserter", [None, cycle_pause]) factory.add_option("backpressure_inserter", [None, cycle_pause]) diff --git a/tb/axis_register/test_axis_register.py b/tb/axis_register/test_axis_register.py index 970630338..198622bd7 100644 --- a/tb/axis_register/test_axis_register.py +++ b/tb/axis_register/test_axis_register.py @@ -110,6 +110,27 @@ async def run_test(dut, payload_lengths=None, payload_data=None, idle_inserter=N await RisingEdge(dut.clk) +async def run_test_tuser_assert(dut): + + tb = TB(dut) + + await tb.reset() + + test_data = bytearray(itertools.islice(itertools.cycle(range(256)), 32)) + test_frame = AxiStreamFrame(test_data, tuser=1) + await tb.source.send(test_frame) + + rx_frame = await tb.sink.recv() + + assert rx_frame.tdata == test_data + assert rx_frame.tuser + + assert tb.sink.empty() + + await RisingEdge(dut.clk) + await RisingEdge(dut.clk) + + async def run_stress_test(dut, idle_inserter=None, backpressure_inserter=None): tb = TB(dut) @@ -175,6 +196,10 @@ def incrementing_payload(length): factory.add_option("backpressure_inserter", [None, cycle_pause]) factory.generate_tests() + for test in [run_test_tuser_assert]: + factory = TestFactory(test) + factory.generate_tests() + factory = TestFactory(run_stress_test) factory.add_option("idle_inserter", [None, cycle_pause]) factory.add_option("backpressure_inserter", [None, cycle_pause]) diff --git a/tb/axis_srl_register/test_axis_srl_register.py b/tb/axis_srl_register/test_axis_srl_register.py index 71c2f1605..de826611d 100644 --- a/tb/axis_srl_register/test_axis_srl_register.py +++ b/tb/axis_srl_register/test_axis_srl_register.py @@ -110,6 +110,27 @@ async def run_test(dut, payload_lengths=None, payload_data=None, idle_inserter=N await RisingEdge(dut.clk) +async def run_test_tuser_assert(dut): + + tb = TB(dut) + + await tb.reset() + + test_data = bytearray(itertools.islice(itertools.cycle(range(256)), 32)) + test_frame = AxiStreamFrame(test_data, tuser=1) + await tb.source.send(test_frame) + + rx_frame = await tb.sink.recv() + + assert rx_frame.tdata == test_data + assert rx_frame.tuser + + assert tb.sink.empty() + + await RisingEdge(dut.clk) + await RisingEdge(dut.clk) + + async def run_stress_test(dut, idle_inserter=None, backpressure_inserter=None): tb = TB(dut) @@ -175,6 +196,10 @@ def incrementing_payload(length): factory.add_option("backpressure_inserter", [None, cycle_pause]) factory.generate_tests() + for test in [run_test_tuser_assert]: + factory = TestFactory(test) + factory.generate_tests() + factory = TestFactory(run_stress_test) factory.add_option("idle_inserter", [None, cycle_pause]) factory.add_option("backpressure_inserter", [None, cycle_pause]) From 8e5c4874eb1c20fd27baf6e8592bf380d675ea6b Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Sun, 30 May 2021 12:10:04 -0700 Subject: [PATCH 05/14] Fix switch wrapper parameters --- rtl/axis_switch_wrap.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/rtl/axis_switch_wrap.py b/rtl/axis_switch_wrap.py index 88cc8e842..c82600fa0 100755 --- a/rtl/axis_switch_wrap.py +++ b/rtl/axis_switch_wrap.py @@ -86,7 +86,7 @@ def generate(ports=4, name=None, output=None): parameter ID_WIDTH = 8, // tdest signal width // must be wide enough to uniquely address outputs - parameter DEST_WIDTH = {{cm}}, + parameter DEST_WIDTH = {{cn}}, // Propagate tuser signal parameter USER_ENABLE = 1, // tuser signal width @@ -145,11 +145,11 @@ def generate(ports=4, name=None, output=None): ); // parameter sizing helpers -function [31:0] w_32(input [31:0] val); - w_32 = val; +function [DEST_WIDTH-1:0] w_dw(input [DEST_WIDTH-1:0] val); + w_dw = val; endfunction -function [S_COUNT-1:0] w_s(input [S_COUNT-1:0] val); +function [{{m-1}}:0] w_s(input [{{m-1}}:0] val); w_s = val; endfunction @@ -164,8 +164,8 @@ def generate(ports=4, name=None, output=None): .DEST_WIDTH(DEST_WIDTH), .USER_ENABLE(USER_ENABLE), .USER_WIDTH(USER_WIDTH), - .M_BASE({ {% for p in range(n-1,-1,-1) %}w_32(M{{'%02d'%p}}_BASE){% if not loop.last %}, {% endif %}{% endfor %} }), - .M_TOP({ {% for p in range(n-1,-1,-1) %}w_32(M{{'%02d'%p}}_TOP){% if not loop.last %}, {% endif %}{% endfor %} }), + .M_BASE({ {% for p in range(n-1,-1,-1) %}w_dw(M{{'%02d'%p}}_BASE){% if not loop.last %}, {% endif %}{% endfor %} }), + .M_TOP({ {% for p in range(n-1,-1,-1) %}w_dw(M{{'%02d'%p}}_TOP){% if not loop.last %}, {% endif %}{% endfor %} }), .M_CONNECT({ {% for p in range(n-1,-1,-1) %}w_s(M{{'%02d'%p}}_CONNECT){% if not loop.last %}, {% endif %}{% endfor %} }), .S_REG_TYPE(S_REG_TYPE), .M_REG_TYPE(M_REG_TYPE), From 56a3b8fe9240155438922bfb6fb5d05b509c844d Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Sun, 30 May 2021 12:11:46 -0700 Subject: [PATCH 06/14] Fix indexed part select error in degenerate case when M_COUNT = 1 --- rtl/axis_ram_switch.v | 15 +++++++++++---- rtl/axis_switch.v | 17 ++++++++++++----- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/rtl/axis_ram_switch.v b/rtl/axis_ram_switch.v index e5bb03c11..d2635e316 100644 --- a/rtl/axis_ram_switch.v +++ b/rtl/axis_ram_switch.v @@ -413,16 +413,23 @@ generate select_valid_next = select_valid_reg && !(port_axis_tvalid && port_axis_tready && port_axis_tlast); if (port_axis_tvalid && !select_valid_reg && !drop_reg) begin - select_next = 1'b0; + select_next = 0; select_valid_next = 1'b0; drop_next = 1'b1; for (k = 0; k < M_COUNT; k = k + 1) begin if (M_BASE == 0) begin - // M_BASE is zero, route with $clog2(M_COUNT) MSBs of tdest as port index - if (port_axis_tdest[DEST_WIDTH-CL_M_COUNT +: CL_M_COUNT] == k && (M_CONNECT & (1 << (m+k*S_COUNT)))) begin - select_next = k; + if (M_COUNT == 1) begin + // M_BASE is zero with only one output port, ignore tdest + select_next = 0; select_valid_next = 1'b1; drop_next = 1'b0; + end else begin + // M_BASE is zero, route with $clog2(M_COUNT) MSBs of tdest as port index + if (port_axis_tdest[DEST_WIDTH-CL_M_COUNT +: CL_M_COUNT] == k && (M_CONNECT & (1 << (m+k*S_COUNT)))) begin + select_next = k; + select_valid_next = 1'b1; + drop_next = 1'b0; + end end end else if (M_TOP == 0) begin // M_TOP is zero, assume equal to M_BASE diff --git a/rtl/axis_switch.v b/rtl/axis_switch.v index 0e785851e..89c93c4ce 100644 --- a/rtl/axis_switch.v +++ b/rtl/axis_switch.v @@ -182,17 +182,24 @@ generate drop_next = drop_reg && !(int_s_axis_tvalid[m] && int_s_axis_tready[m] && int_s_axis_tlast[m]); select_valid_next = select_valid_reg && !(int_s_axis_tvalid[m] && int_s_axis_tready[m] && int_s_axis_tlast[m]); - if (int_s_axis_tvalid[m] && !select_valid_reg) begin - select_next = 1'b0; + if (int_s_axis_tvalid[m] && !select_valid_reg && !drop_reg) begin + select_next = 0; select_valid_next = 1'b0; drop_next = 1'b1; for (k = 0; k < M_COUNT; k = k + 1) begin if (M_BASE == 0) begin - // M_BASE is zero, route with $clog2(M_COUNT) MSBs of tdest as port index - if (int_s_axis_tdest[m*DEST_WIDTH+(DEST_WIDTH-CL_M_COUNT) +: CL_M_COUNT] == k && (M_CONNECT & (1 << (m+k*S_COUNT)))) begin - select_next = k; + if (M_COUNT == 1) begin + // M_BASE is zero with only one output port, ignore tdest + select_next = 0; select_valid_next = 1'b1; drop_next = 1'b0; + end else begin + // M_BASE is zero, route with $clog2(M_COUNT) MSBs of tdest as port index + if (int_s_axis_tdest[m*DEST_WIDTH+(DEST_WIDTH-CL_M_COUNT) +: CL_M_COUNT] == k && (M_CONNECT & (1 << (m+k*S_COUNT)))) begin + select_next = k; + select_valid_next = 1'b1; + drop_next = 1'b0; + end end end else if (M_TOP == 0) begin // M_TOP is zero, assume equal to M_BASE From e3183862bb5b839ab76890622e81e4fddc2c78c3 Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Sun, 30 May 2021 12:12:10 -0700 Subject: [PATCH 07/14] tkeep always active inside RAM switch --- rtl/axis_ram_switch.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtl/axis_ram_switch.v b/rtl/axis_ram_switch.v index d2635e316..eff5df556 100644 --- a/rtl/axis_ram_switch.v +++ b/rtl/axis_ram_switch.v @@ -664,7 +664,7 @@ generate cmd_table_start_addr_end = wr_ptr_cur_reg + 1; cmd_table_start_len = len_reg; cmd_table_start_select = select_reg; - cmd_table_start_tkeep = S_KEEP_ENABLE ? port_axis_tkeep : 1'b1; + cmd_table_start_tkeep = port_axis_tkeep; cmd_table_start_tid = port_axis_tid; cmd_table_start_tdest = port_axis_tdest; cmd_table_start_tuser = port_axis_tuser; From 16b174b4908730f05d86fcc819b8ae111d8cebf1 Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Sun, 30 May 2021 12:19:01 -0700 Subject: [PATCH 08/14] Print addressing configuration --- rtl/axis_ram_switch.v | 15 +++++++++++++++ rtl/axis_switch.v | 15 +++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/rtl/axis_ram_switch.v b/rtl/axis_ram_switch.v index eff5df556..343aac99d 100644 --- a/rtl/axis_ram_switch.v +++ b/rtl/axis_ram_switch.v @@ -184,8 +184,18 @@ initial begin if (M_BASE == 0) begin // M_BASE is zero, route with tdest as port index + $display("Addressing configuration for axis_switch instance %m"); + for (i = 0; i < M_COUNT; i = i + 1) begin + $display("%d: %08x-%08x (connect mask %b)", i, i << (DEST_WIDTH-CL_M_COUNT), ((i+1) << (DEST_WIDTH-CL_M_COUNT))-1, M_CONNECT[i*S_COUNT +: S_COUNT]); + end + end else if (M_TOP == 0) begin // M_TOP is zero, assume equal to M_BASE + $display("Addressing configuration for axis_switch instance %m"); + for (i = 0; i < M_COUNT; i = i + 1) begin + $display("%d: %08x (connect mask %b)", i, M_BASE[i*DEST_WIDTH +: DEST_WIDTH], M_CONNECT[i*S_COUNT +: S_COUNT]); + end + for (i = 0; i < M_COUNT; i = i + 1) begin for (j = i+1; j < M_COUNT; j = j + 1) begin if (M_BASE[i*DEST_WIDTH +: DEST_WIDTH] == M_BASE[j*DEST_WIDTH +: DEST_WIDTH]) begin @@ -197,6 +207,11 @@ initial begin end end end else begin + $display("Addressing configuration for axis_switch instance %m"); + for (i = 0; i < M_COUNT; i = i + 1) begin + $display("%d: %08x-%08x (connect mask %b)", i, M_BASE[i*DEST_WIDTH +: DEST_WIDTH], M_TOP[i*DEST_WIDTH +: DEST_WIDTH], M_CONNECT[i*S_COUNT +: S_COUNT]); + end + for (i = 0; i < M_COUNT; i = i + 1) begin if (M_BASE[i*DEST_WIDTH +: DEST_WIDTH] > M_TOP[i*DEST_WIDTH +: DEST_WIDTH]) begin $error("Error: invalid range (instance %m)"); diff --git a/rtl/axis_switch.v b/rtl/axis_switch.v index 89c93c4ce..0a58a8ef0 100644 --- a/rtl/axis_switch.v +++ b/rtl/axis_switch.v @@ -119,8 +119,18 @@ initial begin if (M_BASE == 0) begin // M_BASE is zero, route with tdest as port index + $display("Addressing configuration for axis_switch instance %m"); + for (i = 0; i < M_COUNT; i = i + 1) begin + $display("%d: %08x-%08x (connect mask %b)", i, i << (DEST_WIDTH-CL_M_COUNT), ((i+1) << (DEST_WIDTH-CL_M_COUNT))-1, M_CONNECT[i*S_COUNT +: S_COUNT]); + end + end else if (M_TOP == 0) begin // M_TOP is zero, assume equal to M_BASE + $display("Addressing configuration for axis_switch instance %m"); + for (i = 0; i < M_COUNT; i = i + 1) begin + $display("%d: %08x (connect mask %b)", i, M_BASE[i*DEST_WIDTH +: DEST_WIDTH], M_CONNECT[i*S_COUNT +: S_COUNT]); + end + for (i = 0; i < M_COUNT; i = i + 1) begin for (j = i+1; j < M_COUNT; j = j + 1) begin if (M_BASE[i*DEST_WIDTH +: DEST_WIDTH] == M_BASE[j*DEST_WIDTH +: DEST_WIDTH]) begin @@ -132,6 +142,11 @@ initial begin end end end else begin + $display("Addressing configuration for axis_switch instance %m"); + for (i = 0; i < M_COUNT; i = i + 1) begin + $display("%d: %08x-%08x (connect mask %b)", i, M_BASE[i*DEST_WIDTH +: DEST_WIDTH], M_TOP[i*DEST_WIDTH +: DEST_WIDTH], M_CONNECT[i*S_COUNT +: S_COUNT]); + end + for (i = 0; i < M_COUNT; i = i + 1) begin if (M_BASE[i*DEST_WIDTH +: DEST_WIDTH] > M_TOP[i*DEST_WIDTH +: DEST_WIDTH]) begin $error("Error: invalid range (instance %m)"); From 9417d5f74955c467d8ad196d59e0b64ce06f6ada Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Sun, 30 May 2021 12:32:02 -0700 Subject: [PATCH 09/14] Use cocotb.top --- tb/axis_adapter/test_axis_adapter.py | 2 +- tb/axis_arb_mux/test_axis_arb_mux.py | 6 +++--- tb/axis_mux/test_axis_mux.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tb/axis_adapter/test_axis_adapter.py b/tb/axis_adapter/test_axis_adapter.py index 2b34c591e..11a2268bf 100644 --- a/tb/axis_adapter/test_axis_adapter.py +++ b/tb/axis_adapter/test_axis_adapter.py @@ -178,7 +178,7 @@ def cycle_pause(): def size_list(): - data_width = max(int(os.getenv("PARAM_S_DATA_WIDTH")), int(os.getenv("PARAM_M_DATA_WIDTH"))) + data_width = max(len(cocotb.top.s_axis_tdata), len(cocotb.top.m_axis_tdata)) byte_width = data_width // 8 return list(range(1, byte_width*4+1))+[512]+[1]*64 diff --git a/tb/axis_arb_mux/test_axis_arb_mux.py b/tb/axis_arb_mux/test_axis_arb_mux.py index 0aa3426a9..cf7e87781 100644 --- a/tb/axis_arb_mux/test_axis_arb_mux.py +++ b/tb/axis_arb_mux/test_axis_arb_mux.py @@ -44,7 +44,7 @@ class TB(object): def __init__(self, dut): self.dut = dut - ports = int(os.getenv("PARAM_PORTS")) + ports = len(dut.axis_arb_mux_inst.s_axis_tvalid) self.log = logging.getLogger("cocotb.tb") self.log.setLevel(logging.DEBUG) @@ -242,7 +242,7 @@ def cycle_pause(): def size_list(): - data_width = int(os.getenv("PARAM_DATA_WIDTH")) + data_width = len(cocotb.top.s00_axis_tdata) byte_width = data_width // 8 return list(range(1, byte_width*4+1))+[512]+[1]*64 @@ -253,7 +253,7 @@ def incrementing_payload(length): if cocotb.SIM_NAME: - ports = int(os.getenv("PARAM_PORTS")) + ports = len(cocotb.top.axis_arb_mux_inst.s_axis_tvalid) factory = TestFactory(run_test) factory.add_option("payload_lengths", [size_list]) diff --git a/tb/axis_mux/test_axis_mux.py b/tb/axis_mux/test_axis_mux.py index 777d95f8f..12a06efa0 100644 --- a/tb/axis_mux/test_axis_mux.py +++ b/tb/axis_mux/test_axis_mux.py @@ -43,7 +43,7 @@ class TB(object): def __init__(self, dut): self.dut = dut - ports = int(os.getenv("PORTS")) + ports = len(dut.axis_mux_inst.s_axis_tvalid) self.log = logging.getLogger("cocotb.tb") self.log.setLevel(logging.DEBUG) @@ -159,7 +159,7 @@ def incrementing_payload(length): if cocotb.SIM_NAME: - ports = int(os.getenv("PORTS")) + ports = len(cocotb.top.axis_mux_inst.s_axis_tvalid) factory = TestFactory(run_test) factory.add_option("payload_lengths", [size_list]) From 34d5a4fed59eb32ec0a8759e872b71658d448dca Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Sun, 30 May 2021 12:32:26 -0700 Subject: [PATCH 10/14] Add wrapper generator for RAM switch --- rtl/axis_ram_switch_wrap.py | 258 ++++++++++++++++++++++++++++++++++++ 1 file changed, 258 insertions(+) create mode 100755 rtl/axis_ram_switch_wrap.py diff --git a/rtl/axis_ram_switch_wrap.py b/rtl/axis_ram_switch_wrap.py new file mode 100755 index 000000000..32bbd8e3c --- /dev/null +++ b/rtl/axis_ram_switch_wrap.py @@ -0,0 +1,258 @@ +#!/usr/bin/env python +""" +Generates an AXI Stream switch wrapper with the specified number of ports +""" + +import argparse +from jinja2 import Template + + +def main(): + parser = argparse.ArgumentParser(description=__doc__.strip()) + parser.add_argument('-p', '--ports', type=int, default=[4], nargs='+', help="number of ports") + parser.add_argument('-n', '--name', type=str, help="module name") + parser.add_argument('-o', '--output', type=str, help="output file name") + + args = parser.parse_args() + + try: + generate(**args.__dict__) + except IOError as ex: + print(ex) + exit(1) + + +def generate(ports=4, name=None, output=None): + if type(ports) is int: + m = n = ports + elif len(ports) == 1: + m = n = ports[0] + else: + m, n = ports + + if name is None: + name = "axis_ram_switch_wrap_{0}x{1}".format(m, n) + + if output is None: + output = name + ".v" + + print("Generating {0}x{1} port AXI stream RAM switch wrapper {2}...".format(m, n, name)) + + cm = (m-1).bit_length() + cn = (n-1).bit_length() + + t = Template(u"""/* + +Copyright (c) 2018-2021 Alex Forencich + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +// Language: Verilog 2001 + +`timescale 1ns / 1ps + +/* + * AXI4-Stream {{m}}x{{n}} RAM switch (wrapper) + */ +module {{name}} # +( + // FIFO depth in words (each virtual FIFO) + // KEEP_WIDTH words per cycle if KEEP_ENABLE set + // Rounded up to nearest power of 2 cycles + parameter FIFO_DEPTH = 4096, + // Command FIFO depth (each virtual FIFO) + // Rounded up to nearest power of 2 + parameter CMD_FIFO_DEPTH = 32, + // Speedup factor (internal data width scaling factor) + // Speedup of 0 scales internal width to provide maximum bandwidth + parameter SPEEDUP = 0, + // Width of input AXI stream interfaces in bits + parameter S_DATA_WIDTH = 8, + // Propagate tkeep signal + parameter S_KEEP_ENABLE = (S_DATA_WIDTH>8), + // tkeep signal width (words per cycle) + parameter S_KEEP_WIDTH = (S_DATA_WIDTH/8), + // Width of output AXI stream interfaces in bits + parameter M_DATA_WIDTH = 8, + // Propagate tkeep signal + parameter M_KEEP_ENABLE = (M_DATA_WIDTH>8), + // tkeep signal width (words per cycle) + parameter M_KEEP_WIDTH = (M_DATA_WIDTH/8), + // Propagate tid signal + parameter ID_ENABLE = 0, + // tid signal width + parameter ID_WIDTH = 8, + // tdest signal width + // must be wide enough to uniquely address outputs + parameter DEST_WIDTH = {{cn}}, + // Propagate tuser signal + parameter USER_ENABLE = 1, + // tuser signal width + parameter USER_WIDTH = 1, + // tuser value for bad frame marker + parameter USER_BAD_FRAME_VALUE = 1'b1, + // tuser mask for bad frame marker + parameter USER_BAD_FRAME_MASK = 1'b1, + // Drop frames marked bad + parameter DROP_BAD_FRAME = 0, + // Drop incoming frames when full + // When set, s_axis_tready is always asserted + parameter DROP_WHEN_FULL = 0, +{%- for p in range(n) %} + // Output interface routing base tdest selection + // Port selected if M_BASE <= tdest <= M_TOP + parameter M{{'%02d'%p}}_BASE = {{p}}, + // Output interface routing top tdest selection + // Port selected if M_BASE <= tdest <= M_TOP + parameter M{{'%02d'%p}}_TOP = {{p}}, + // Interface connection control + parameter M{{'%02d'%p}}_CONNECT = {{m}}'b{% for p in range(m) %}1{% endfor %}, +{%- endfor %} + // arbitration type: "PRIORITY" or "ROUND_ROBIN" + parameter ARB_TYPE = "ROUND_ROBIN", + // LSB priority: "LOW", "HIGH" + parameter LSB_PRIORITY = "HIGH", + // RAM read data output pipeline stages + parameter RAM_PIPELINE = 2 +) +( + input wire clk, + input wire rst, + + /* + * AXI Stream inputs + */ +{%- for p in range(m) %} + input wire [S_DATA_WIDTH-1:0] s{{'%02d'%p}}_axis_tdata, + input wire [S_KEEP_WIDTH-1:0] s{{'%02d'%p}}_axis_tkeep, + input wire s{{'%02d'%p}}_axis_tvalid, + output wire s{{'%02d'%p}}_axis_tready, + input wire s{{'%02d'%p}}_axis_tlast, + input wire [ID_WIDTH-1:0] s{{'%02d'%p}}_axis_tid, + input wire [DEST_WIDTH-1:0] s{{'%02d'%p}}_axis_tdest, + input wire [USER_WIDTH-1:0] s{{'%02d'%p}}_axis_tuser, +{% endfor %} + /* + * AXI Stream outputs + */ +{%- for p in range(n) %} + output wire [M_DATA_WIDTH-1:0] m{{'%02d'%p}}_axis_tdata, + output wire [M_KEEP_WIDTH-1:0] m{{'%02d'%p}}_axis_tkeep, + output wire m{{'%02d'%p}}_axis_tvalid, + input wire m{{'%02d'%p}}_axis_tready, + output wire m{{'%02d'%p}}_axis_tlast, + output wire [ID_WIDTH-1:0] m{{'%02d'%p}}_axis_tid, + output wire [DEST_WIDTH-1:0] m{{'%02d'%p}}_axis_tdest, + output wire [USER_WIDTH-1:0] m{{'%02d'%p}}_axis_tuser, +{% endfor %} + /* + * Status + */ + output wire [{{m-1}}:0] status_overflow, + output wire [{{m-1}}:0] status_bad_frame, + output wire [{{m-1}}:0] status_good_frame +); + +// parameter sizing helpers +function [DEST_WIDTH-1:0] w_dw(input [DEST_WIDTH-1:0] val); + w_dw = val; +endfunction + +function [{{m-1}}:0] w_s(input [{{m-1}}:0] val); + w_s = val; +endfunction + +axis_ram_switch #( + .FIFO_DEPTH(FIFO_DEPTH), + .CMD_FIFO_DEPTH(CMD_FIFO_DEPTH), + .SPEEDUP(SPEEDUP), + .S_COUNT({{m}}), + .M_COUNT({{n}}), + .S_DATA_WIDTH(S_DATA_WIDTH), + .S_KEEP_ENABLE(S_KEEP_ENABLE), + .S_KEEP_WIDTH(S_KEEP_WIDTH), + .M_DATA_WIDTH(M_DATA_WIDTH), + .M_KEEP_ENABLE(M_KEEP_ENABLE), + .M_KEEP_WIDTH(M_KEEP_WIDTH), + .ID_ENABLE(ID_ENABLE), + .ID_WIDTH(ID_WIDTH), + .DEST_WIDTH(DEST_WIDTH), + .USER_ENABLE(USER_ENABLE), + .USER_WIDTH(USER_WIDTH), + .USER_BAD_FRAME_VALUE(USER_BAD_FRAME_VALUE), + .USER_BAD_FRAME_MASK(USER_BAD_FRAME_MASK), + .DROP_BAD_FRAME(DROP_BAD_FRAME), + .DROP_WHEN_FULL(DROP_WHEN_FULL), + .M_BASE({ {% for p in range(n-1,-1,-1) %}w_dw(M{{'%02d'%p}}_BASE){% if not loop.last %}, {% endif %}{% endfor %} }), + .M_TOP({ {% for p in range(n-1,-1,-1) %}w_dw(M{{'%02d'%p}}_TOP){% if not loop.last %}, {% endif %}{% endfor %} }), + .M_CONNECT({ {% for p in range(n-1,-1,-1) %}w_s(M{{'%02d'%p}}_CONNECT){% if not loop.last %}, {% endif %}{% endfor %} }), + .ARB_TYPE(ARB_TYPE), + .LSB_PRIORITY(LSB_PRIORITY), + .RAM_PIPELINE(RAM_PIPELINE) +) +axis_ram_switch_inst ( + .clk(clk), + .rst(rst), + // AXI inputs + .s_axis_tdata({ {% for p in range(m-1,-1,-1) %}s{{'%02d'%p}}_axis_tdata{% if not loop.last %}, {% endif %}{% endfor %} }), + .s_axis_tkeep({ {% for p in range(m-1,-1,-1) %}s{{'%02d'%p}}_axis_tkeep{% if not loop.last %}, {% endif %}{% endfor %} }), + .s_axis_tvalid({ {% for p in range(m-1,-1,-1) %}s{{'%02d'%p}}_axis_tvalid{% if not loop.last %}, {% endif %}{% endfor %} }), + .s_axis_tready({ {% for p in range(m-1,-1,-1) %}s{{'%02d'%p}}_axis_tready{% if not loop.last %}, {% endif %}{% endfor %} }), + .s_axis_tlast({ {% for p in range(m-1,-1,-1) %}s{{'%02d'%p}}_axis_tlast{% if not loop.last %}, {% endif %}{% endfor %} }), + .s_axis_tid({ {% for p in range(m-1,-1,-1) %}s{{'%02d'%p}}_axis_tid{% if not loop.last %}, {% endif %}{% endfor %} }), + .s_axis_tdest({ {% for p in range(m-1,-1,-1) %}s{{'%02d'%p}}_axis_tdest{% if not loop.last %}, {% endif %}{% endfor %} }), + .s_axis_tuser({ {% for p in range(m-1,-1,-1) %}s{{'%02d'%p}}_axis_tuser{% if not loop.last %}, {% endif %}{% endfor %} }), + // AXI outputs + .m_axis_tdata({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axis_tdata{% if not loop.last %}, {% endif %}{% endfor %} }), + .m_axis_tkeep({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axis_tkeep{% if not loop.last %}, {% endif %}{% endfor %} }), + .m_axis_tvalid({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axis_tvalid{% if not loop.last %}, {% endif %}{% endfor %} }), + .m_axis_tready({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axis_tready{% if not loop.last %}, {% endif %}{% endfor %} }), + .m_axis_tlast({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axis_tlast{% if not loop.last %}, {% endif %}{% endfor %} }), + .m_axis_tid({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axis_tid{% if not loop.last %}, {% endif %}{% endfor %} }), + .m_axis_tdest({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axis_tdest{% if not loop.last %}, {% endif %}{% endfor %} }), + .m_axis_tuser({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axis_tuser{% if not loop.last %}, {% endif %}{% endfor %} }), + // Status + .status_overflow(status_overflow), + .status_bad_frame(status_bad_frame), + .status_good_frame(status_good_frame) +); + +endmodule + +""") + + print(f"Writing file '{output}'...") + + with open(output, 'w') as f: + f.write(t.render( + m=m, + n=n, + cm=cm, + cn=cn, + name=name + )) + f.flush() + + print("Done") + + +if __name__ == "__main__": + main() From 5d9c982cd457e5b2ce21195521d7883d2fbd6306 Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Sun, 30 May 2021 12:33:29 -0700 Subject: [PATCH 11/14] Add switch testbenches --- tb/axis_ram_switch/Makefile | 134 ++++++++ tb/axis_ram_switch/test_axis_ram_switch.py | 361 +++++++++++++++++++++ tb/axis_switch/Makefile | 107 ++++++ tb/axis_switch/test_axis_switch.py | 351 ++++++++++++++++++++ 4 files changed, 953 insertions(+) create mode 100644 tb/axis_ram_switch/Makefile create mode 100644 tb/axis_ram_switch/test_axis_ram_switch.py create mode 100644 tb/axis_switch/Makefile create mode 100644 tb/axis_switch/test_axis_switch.py diff --git a/tb/axis_ram_switch/Makefile b/tb/axis_ram_switch/Makefile new file mode 100644 index 000000000..79e898ce6 --- /dev/null +++ b/tb/axis_ram_switch/Makefile @@ -0,0 +1,134 @@ +# Copyright (c) 2021 Alex Forencich +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +TOPLEVEL_LANG = verilog + +SIM ?= icarus +WAVES ?= 0 + +COCOTB_HDL_TIMEUNIT = 1ns +COCOTB_HDL_TIMEPRECISION = 1ps + +export PARAM_S_COUNT ?= 4 +export PARAM_M_COUNT ?= 4 + +DUT = axis_ram_switch +WRAPPER = $(DUT)_wrap_$(PARAM_S_COUNT)x$(PARAM_M_COUNT) +TOPLEVEL = $(WRAPPER) +MODULE = test_$(DUT) +VERILOG_SOURCES += $(WRAPPER).v +VERILOG_SOURCES += ../../rtl/$(DUT).v +VERILOG_SOURCES += ../../rtl/axis_adapter.v +VERILOG_SOURCES += ../../rtl/arbiter.v +VERILOG_SOURCES += ../../rtl/priority_encoder.v + +# module parameters +export PARAM_FIFO_DEPTH ?= 4096 +export PARAM_CMD_FIFO_DEPTH ?= 32 +export PARAM_SPEEDUP ?= 0 +export PARAM_S_DATA_WIDTH ?= 8 +export PARAM_S_KEEP_ENABLE ?= $(shell expr $(PARAM_S_DATA_WIDTH) \> 8 ) +export PARAM_S_KEEP_WIDTH ?= $(shell expr $(PARAM_S_DATA_WIDTH) / 8 ) +export PARAM_M_DATA_WIDTH ?= 8 +export PARAM_M_KEEP_ENABLE ?= $(shell expr $(PARAM_M_DATA_WIDTH) \> 8 ) +export PARAM_M_KEEP_WIDTH ?= $(shell expr $(PARAM_M_DATA_WIDTH) / 8 ) +export PARAM_ID_ENABLE ?= 1 +export PARAM_ID_WIDTH ?= 16 +export PARAM_DEST_WIDTH ?= 8 +export PARAM_USER_ENABLE ?= 1 +export PARAM_USER_WIDTH ?= 1 +export PARAM_USER_BAD_FRAME_VALUE ?= 1 +export PARAM_USER_BAD_FRAME_MASK ?= 1 +export PARAM_DROP_BAD_FRAME ?= 0 +export PARAM_DROP_WHEN_FULL ?= 0 +export PARAM_RAM_PIPELINE ?= 2 + +ifeq ($(SIM), icarus) + PLUSARGS += -fst + + COMPILE_ARGS += -P $(TOPLEVEL).FIFO_DEPTH=$(PARAM_FIFO_DEPTH) + COMPILE_ARGS += -P $(TOPLEVEL).CMD_FIFO_DEPTH=$(PARAM_CMD_FIFO_DEPTH) + COMPILE_ARGS += -P $(TOPLEVEL).SPEEDUP=$(PARAM_SPEEDUP) + COMPILE_ARGS += -P $(TOPLEVEL).S_DATA_WIDTH=$(PARAM_S_DATA_WIDTH) + COMPILE_ARGS += -P $(TOPLEVEL).S_KEEP_ENABLE=$(PARAM_S_KEEP_ENABLE) + COMPILE_ARGS += -P $(TOPLEVEL).S_KEEP_WIDTH=$(PARAM_S_KEEP_WIDTH) + COMPILE_ARGS += -P $(TOPLEVEL).M_DATA_WIDTH=$(PARAM_M_DATA_WIDTH) + COMPILE_ARGS += -P $(TOPLEVEL).M_KEEP_ENABLE=$(PARAM_M_KEEP_ENABLE) + COMPILE_ARGS += -P $(TOPLEVEL).M_KEEP_WIDTH=$(PARAM_M_KEEP_WIDTH) + COMPILE_ARGS += -P $(TOPLEVEL).ID_ENABLE=$(PARAM_ID_ENABLE) + COMPILE_ARGS += -P $(TOPLEVEL).ID_WIDTH=$(PARAM_ID_WIDTH) + COMPILE_ARGS += -P $(TOPLEVEL).DEST_WIDTH=$(PARAM_DEST_WIDTH) + COMPILE_ARGS += -P $(TOPLEVEL).USER_ENABLE=$(PARAM_USER_ENABLE) + COMPILE_ARGS += -P $(TOPLEVEL).USER_WIDTH=$(PARAM_USER_WIDTH) + COMPILE_ARGS += -P $(TOPLEVEL).USER_BAD_FRAME_VALUE=$(PARAM_USER_BAD_FRAME_VALUE) + COMPILE_ARGS += -P $(TOPLEVEL).USER_BAD_FRAME_MASK=$(PARAM_USER_BAD_FRAME_MASK) + COMPILE_ARGS += -P $(TOPLEVEL).DROP_BAD_FRAME=$(PARAM_DROP_BAD_FRAME) + COMPILE_ARGS += -P $(TOPLEVEL).DROP_WHEN_FULL=$(PARAM_DROP_WHEN_FULL) + COMPILE_ARGS += -P $(TOPLEVEL).RAM_PIPELINE=$(PARAM_RAM_PIPELINE) + + ifeq ($(WAVES), 1) + VERILOG_SOURCES += iverilog_dump.v + COMPILE_ARGS += -s iverilog_dump + endif +else ifeq ($(SIM), verilator) + COMPILE_ARGS += -Wno-SELRANGE -Wno-WIDTH + + COMPILE_ARGS += -GFIFO_DEPTH=$(PARAM_FIFO_DEPTH) + COMPILE_ARGS += -GCMD_FIFO_DEPTH=$(PARAM_CMD_FIFO_DEPTH) + COMPILE_ARGS += -GSPEEDUP=$(PARAM_SPEEDUP) + COMPILE_ARGS += -GS_DATA_WIDTH=$(PARAM_S_DATA_WIDTH) + COMPILE_ARGS += -GS_KEEP_ENABLE=$(PARAM_S_KEEP_ENABLE) + COMPILE_ARGS += -GS_KEEP_WIDTH=$(PARAM_S_KEEP_WIDTH) + COMPILE_ARGS += -GM_DATA_WIDTH=$(PARAM_M_DATA_WIDTH) + COMPILE_ARGS += -GM_KEEP_ENABLE=$(PARAM_M_KEEP_ENABLE) + COMPILE_ARGS += -GM_KEEP_WIDTH=$(PARAM_M_KEEP_WIDTH) + COMPILE_ARGS += -GID_ENABLE=$(PARAM_ID_ENABLE) + COMPILE_ARGS += -GID_WIDTH=$(PARAM_ID_WIDTH) + COMPILE_ARGS += -GDEST_WIDTH=$(PARAM_DEST_WIDTH) + COMPILE_ARGS += -GUSER_ENABLE=$(PARAM_USER_ENABLE) + COMPILE_ARGS += -GUSER_WIDTH=$(PARAM_USER_WIDTH) + COMPILE_ARGS += -GUSER_BAD_FRAME_VALUE=$(PARAM_USER_BAD_FRAME_VALUE) + COMPILE_ARGS += -GUSER_BAD_FRAME_MASK=$(PARAM_USER_BAD_FRAME_MASK) + COMPILE_ARGS += -GDROP_BAD_FRAME=$(PARAM_DROP_BAD_FRAME) + COMPILE_ARGS += -GDROP_WHEN_FULL=$(PARAM_DROP_WHEN_FULL) + COMPILE_ARGS += -GRAM_PIPELINE=$(PARAM_RAM_PIPELINE) + + ifeq ($(WAVES), 1) + COMPILE_ARGS += --trace-fst + endif +endif + +include $(shell cocotb-config --makefiles)/Makefile.sim + +$(WRAPPER).v: ../../rtl/$(DUT)_wrap.py + $< -p $(PARAM_S_COUNT) $(PARAM_M_COUNT) + +iverilog_dump.v: + echo 'module iverilog_dump();' > $@ + echo 'initial begin' >> $@ + echo ' $$dumpfile("$(TOPLEVEL).fst");' >> $@ + echo ' $$dumpvars(0, $(TOPLEVEL));' >> $@ + echo 'end' >> $@ + echo 'endmodule' >> $@ + +clean:: + @rm -rf iverilog_dump.v + @rm -rf dump.fst $(TOPLEVEL).fst + @rm -rf *_wrap_*.v diff --git a/tb/axis_ram_switch/test_axis_ram_switch.py b/tb/axis_ram_switch/test_axis_ram_switch.py new file mode 100644 index 000000000..adc4ab699 --- /dev/null +++ b/tb/axis_ram_switch/test_axis_ram_switch.py @@ -0,0 +1,361 @@ +#!/usr/bin/env python +""" + +Copyright (c) 2021 Alex Forencich + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +""" + +import itertools +import logging +import os +import random +import subprocess + +import cocotb_test.simulator +import pytest + +import cocotb +from cocotb.clock import Clock +from cocotb.triggers import RisingEdge, Event +from cocotb.regression import TestFactory + +from cocotbext.axi import AxiStreamBus, AxiStreamFrame, AxiStreamSource, AxiStreamSink + + +class TB(object): + def __init__(self, dut): + self.dut = dut + + s_count = len(dut.axis_ram_switch_inst.s_axis_tvalid) + m_count = len(dut.axis_ram_switch_inst.m_axis_tvalid) + + self.log = logging.getLogger("cocotb.tb") + self.log.setLevel(logging.DEBUG) + + cocotb.fork(Clock(dut.clk, 10, units="ns").start()) + + self.source = [AxiStreamSource(AxiStreamBus.from_prefix(dut, f"s{k:02d}_axis"), dut.clk, dut.rst) for k in range(s_count)] + self.sink = [AxiStreamSink(AxiStreamBus.from_prefix(dut, f"m{k:02d}_axis"), dut.clk, dut.rst) for k in range(m_count)] + + def set_idle_generator(self, generator=None): + if generator: + for source in self.source: + source.set_pause_generator(generator()) + + def set_backpressure_generator(self, generator=None): + if generator: + for sink in self.sink: + sink.set_pause_generator(generator()) + + async def reset(self): + self.dut.rst.setimmediatevalue(0) + await RisingEdge(self.dut.clk) + await RisingEdge(self.dut.clk) + self.dut.rst <= 1 + await RisingEdge(self.dut.clk) + await RisingEdge(self.dut.clk) + self.dut.rst <= 0 + await RisingEdge(self.dut.clk) + await RisingEdge(self.dut.clk) + + +async def run_test(dut, payload_lengths=None, payload_data=None, idle_inserter=None, backpressure_inserter=None, s=0, m=0): + + tb = TB(dut) + + id_count = 2**len(tb.source[s].bus.tid) + + cur_id = 1 + + await tb.reset() + + tb.set_idle_generator(idle_inserter) + tb.set_backpressure_generator(backpressure_inserter) + + test_frames = [] + + for test_data in [payload_data(x) for x in payload_lengths()]: + test_frame = AxiStreamFrame(test_data) + test_frame.tid = cur_id + test_frame.tdest = m + + test_frames.append(test_frame) + await tb.source[s].send(test_frame) + + cur_id = (cur_id + 1) % id_count + + for test_frame in test_frames: + rx_frame = await tb.sink[m].recv() + + assert rx_frame.tdata == test_frame.tdata + assert rx_frame.tid == test_frame.tid + assert rx_frame.tdest == test_frame.tdest + assert not rx_frame.tuser + + assert all(s.empty() for s in tb.sink) + + await RisingEdge(dut.clk) + await RisingEdge(dut.clk) + + +async def run_test_tuser_assert(dut, s=0, m=0): + + tb = TB(dut) + + await tb.reset() + + test_data = bytearray(itertools.islice(itertools.cycle(range(256)), 32)) + test_frame = AxiStreamFrame(test_data, tuser=1, tdest=m) + await tb.source[s].send(test_frame) + + rx_frame = await tb.sink[m].recv() + + assert rx_frame.tdata == test_data + assert rx_frame.tuser + + assert all(s.empty() for s in tb.sink) + + await RisingEdge(dut.clk) + await RisingEdge(dut.clk) + + +async def run_arb_test(dut): + + tb = TB(dut) + + byte_lanes = max(tb.source[0].byte_lanes, tb.sink[0].byte_lanes) + id_count = 2**len(tb.source[0].bus.tid) + + cur_id = 1 + + await tb.reset() + + test_frames = [] + + length = byte_lanes*16 + test_data = bytearray(itertools.islice(itertools.cycle(range(256)), length)) + + for k in range(5): + test_frame = AxiStreamFrame(test_data, tx_complete=Event()) + test_frame.tid = cur_id + test_frame.tdest = 0 + + src_ind = 0 + + if k == 0: + src_ind = 0 + elif k == 4: + await test_frames[1].tx_complete.wait() + for j in range(8): + await RisingEdge(dut.clk) + src_ind = 0 + else: + src_ind = 1 + + test_frames.append(test_frame) + await tb.source[src_ind].send(test_frame) + + cur_id = (cur_id + 1) % id_count + + for k in [0, 1, 2, 4, 3]: + test_frame = test_frames[k] + rx_frame = await tb.sink[0].recv() + + assert rx_frame.tdata == test_frame.tdata + assert rx_frame.tid == test_frame.tid + assert rx_frame.tdest == test_frame.tdest + assert not rx_frame.tuser + + assert all(s.empty() for s in tb.sink) + + await RisingEdge(dut.clk) + await RisingEdge(dut.clk) + + +async def run_stress_test(dut, idle_inserter=None, backpressure_inserter=None): + + tb = TB(dut) + + byte_lanes = max(tb.source[0].byte_lanes, tb.sink[0].byte_lanes) + id_count = 2**len(tb.source[0].bus.tid) + + cur_id = 1 + + await tb.reset() + + tb.set_idle_generator(idle_inserter) + tb.set_backpressure_generator(backpressure_inserter) + + test_frames = [[list() for y in tb.sink] for x in tb.source] + + for p in range(len(tb.source)): + for k in range(128): + length = random.randint(1, byte_lanes*16) + test_data = bytearray(itertools.islice(itertools.cycle(range(256)), length)) + test_frame = AxiStreamFrame(test_data) + test_frame.tid = cur_id + test_frame.tdest = random.randrange(len(tb.sink)) + + test_frames[p][test_frame.tdest].append(test_frame) + await tb.source[p].send(test_frame) + + cur_id = (cur_id + 1) % id_count + + for lst in test_frames: + while any(lst): + rx_frame = await tb.sink[[x for x in lst if x][0][0].tdest].recv() + + test_frame = None + + for lst_a in test_frames: + for lst_b in lst_a: + if lst_b and lst_b[0].tid == rx_frame.tid: + test_frame = lst_b.pop(0) + break + + assert test_frame is not None + + assert rx_frame.tdata == test_frame.tdata + assert rx_frame.tid == test_frame.tid + assert rx_frame.tdest == test_frame.tdest + assert not rx_frame.tuser + + assert all(s.empty() for s in tb.sink) + + await RisingEdge(dut.clk) + await RisingEdge(dut.clk) + + +def cycle_pause(): + return itertools.cycle([1, 1, 1, 0]) + + +def size_list(): + data_width = max(len(cocotb.top.s00_axis_tdata), len(cocotb.top.m00_axis_tdata)) + byte_width = data_width // 8 + return list(range(1, byte_width*4+1))+[512]+[1]*64 + + +def incrementing_payload(length): + return bytearray(itertools.islice(itertools.cycle(range(256)), length)) + + +if cocotb.SIM_NAME: + + s_count = len(cocotb.top.axis_ram_switch_inst.s_axis_tvalid) + m_count = len(cocotb.top.axis_ram_switch_inst.m_axis_tvalid) + + factory = TestFactory(run_test) + factory.add_option("payload_lengths", [size_list]) + factory.add_option("payload_data", [incrementing_payload]) + factory.add_option("idle_inserter", [None, cycle_pause]) + factory.add_option("backpressure_inserter", [None, cycle_pause]) + factory.add_option("s", range(min(s_count, 2))) + factory.add_option("m", range(min(m_count, 2))) + factory.generate_tests() + + for test in [run_test_tuser_assert]: + factory = TestFactory(test) + factory.add_option("s", range(min(s_count, 2))) + factory.add_option("m", range(min(m_count, 2))) + factory.generate_tests() + + if s_count > 1: + factory = TestFactory(run_arb_test) + factory.generate_tests() + + factory = TestFactory(run_stress_test) + factory.add_option("idle_inserter", [None, cycle_pause]) + factory.add_option("backpressure_inserter", [None, cycle_pause]) + factory.generate_tests() + + +# cocotb-test + +tests_dir = os.path.dirname(__file__) +rtl_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'rtl')) + + +@pytest.mark.parametrize("m_data_width", [8, 32]) +@pytest.mark.parametrize("s_data_width", [8, 32]) +@pytest.mark.parametrize("m_count", [1, 4]) +@pytest.mark.parametrize("s_count", [1, 4]) +def test_axis_ram_switch(request, s_count, m_count, s_data_width, m_data_width): + dut = "axis_ram_switch" + wrapper = f"{dut}_wrap_{s_count}x{m_count}" + module = os.path.splitext(os.path.basename(__file__))[0] + toplevel = wrapper + + # generate wrapper + wrapper_file = os.path.join(tests_dir, f"{wrapper}.v") + if not os.path.exists(wrapper_file): + subprocess.Popen( + [os.path.join(rtl_dir, f"{dut}_wrap.py"), "-p", f"{s_count}", f"{m_count}"], + cwd=tests_dir + ).wait() + + verilog_sources = [ + wrapper_file, + os.path.join(rtl_dir, f"{dut}.v"), + os.path.join(rtl_dir, "axis_adapter.v"), + os.path.join(rtl_dir, "arbiter.v"), + os.path.join(rtl_dir, "priority_encoder.v"), + ] + + parameters = {} + + parameters['S_COUNT'] = s_count + parameters['M_COUNT'] = m_count + + parameters['FIFO_DEPTH'] = 4096 + parameters['CMD_FIFO_DEPTH'] = 32 + parameters['SPEEDUP'] = 0 + parameters['S_DATA_WIDTH'] = s_data_width + parameters['S_KEEP_ENABLE'] = int(parameters['S_DATA_WIDTH'] > 8) + parameters['S_KEEP_WIDTH'] = parameters['S_DATA_WIDTH'] // 8 + parameters['M_DATA_WIDTH'] = m_data_width + parameters['M_KEEP_ENABLE'] = int(parameters['M_DATA_WIDTH'] > 8) + parameters['M_KEEP_WIDTH'] = parameters['M_DATA_WIDTH'] // 8 + parameters['ID_ENABLE'] = 1 + parameters['ID_WIDTH'] = 16 + parameters['DEST_WIDTH'] = 8 + parameters['USER_ENABLE'] = 1 + parameters['USER_WIDTH'] = 1 + parameters['USER_BAD_FRAME_VALUE'] = 1 + parameters['USER_BAD_FRAME_MASK'] = 1 + parameters['DROP_BAD_FRAME'] = 0 + parameters['DROP_WHEN_FULL'] = 0 + parameters['RAM_PIPELINE'] = 2 + + extra_env = {f'PARAM_{k}': str(v) for k, v in parameters.items()} + + sim_build = os.path.join(tests_dir, "sim_build", + request.node.name.replace('[', '-').replace(']', '')) + + cocotb_test.simulator.run( + python_search=[tests_dir], + verilog_sources=verilog_sources, + toplevel=toplevel, + module=module, + parameters=parameters, + sim_build=sim_build, + extra_env=extra_env, + ) diff --git a/tb/axis_switch/Makefile b/tb/axis_switch/Makefile new file mode 100644 index 000000000..cd925f645 --- /dev/null +++ b/tb/axis_switch/Makefile @@ -0,0 +1,107 @@ +# Copyright (c) 2021 Alex Forencich +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +TOPLEVEL_LANG = verilog + +SIM ?= icarus +WAVES ?= 0 + +COCOTB_HDL_TIMEUNIT = 1ns +COCOTB_HDL_TIMEPRECISION = 1ps + +export PARAM_S_COUNT ?= 4 +export PARAM_M_COUNT ?= 4 + +DUT = axis_switch +WRAPPER = $(DUT)_wrap_$(PARAM_S_COUNT)x$(PARAM_M_COUNT) +TOPLEVEL = $(WRAPPER) +MODULE = test_$(DUT) +VERILOG_SOURCES += $(WRAPPER).v +VERILOG_SOURCES += ../../rtl/$(DUT).v +VERILOG_SOURCES += ../../rtl/axis_register.v +VERILOG_SOURCES += ../../rtl/arbiter.v +VERILOG_SOURCES += ../../rtl/priority_encoder.v + +# module parameters +export PARAM_DATA_WIDTH ?= 8 +export PARAM_KEEP_ENABLE ?= $(shell expr $(PARAM_DATA_WIDTH) \> 8 ) +export PARAM_KEEP_WIDTH ?= $(shell expr $(PARAM_DATA_WIDTH) / 8 ) +export PARAM_ID_ENABLE ?= 1 +export PARAM_ID_WIDTH ?= 16 +export PARAM_DEST_WIDTH ?= 8 +export PARAM_USER_ENABLE ?= 1 +export PARAM_USER_WIDTH ?= 1 +export PARAM_S_REG_TYPE ?= 0 +export PARAM_M_REG_TYPE ?= 2 + +ifeq ($(SIM), icarus) + PLUSARGS += -fst + + COMPILE_ARGS += -P $(TOPLEVEL).DATA_WIDTH=$(PARAM_DATA_WIDTH) + COMPILE_ARGS += -P $(TOPLEVEL).KEEP_ENABLE=$(PARAM_KEEP_ENABLE) + COMPILE_ARGS += -P $(TOPLEVEL).KEEP_WIDTH=$(PARAM_KEEP_WIDTH) + COMPILE_ARGS += -P $(TOPLEVEL).ID_ENABLE=$(PARAM_ID_ENABLE) + COMPILE_ARGS += -P $(TOPLEVEL).ID_WIDTH=$(PARAM_ID_WIDTH) + COMPILE_ARGS += -P $(TOPLEVEL).DEST_WIDTH=$(PARAM_DEST_WIDTH) + COMPILE_ARGS += -P $(TOPLEVEL).USER_ENABLE=$(PARAM_USER_ENABLE) + COMPILE_ARGS += -P $(TOPLEVEL).USER_WIDTH=$(PARAM_USER_WIDTH) + COMPILE_ARGS += -P $(TOPLEVEL).S_REG_TYPE=$(PARAM_S_REG_TYPE) + COMPILE_ARGS += -P $(TOPLEVEL).M_REG_TYPE=$(PARAM_M_REG_TYPE) + + ifeq ($(WAVES), 1) + VERILOG_SOURCES += iverilog_dump.v + COMPILE_ARGS += -s iverilog_dump + endif +else ifeq ($(SIM), verilator) + COMPILE_ARGS += -Wno-SELRANGE -Wno-WIDTH + + COMPILE_ARGS += -GDATA_WIDTH=$(PARAM_DATA_WIDTH) + COMPILE_ARGS += -GKEEP_ENABLE=$(PARAM_KEEP_ENABLE) + COMPILE_ARGS += -GKEEP_WIDTH=$(PARAM_KEEP_WIDTH) + COMPILE_ARGS += -GID_ENABLE=$(PARAM_ID_ENABLE) + COMPILE_ARGS += -GID_WIDTH=$(PARAM_ID_WIDTH) + COMPILE_ARGS += -GDEST_WIDTH=$(PARAM_DEST_WIDTH) + COMPILE_ARGS += -GUSER_ENABLE=$(PARAM_USER_ENABLE) + COMPILE_ARGS += -GUSER_WIDTH=$(PARAM_USER_WIDTH) + COMPILE_ARGS += -GS_REG_TYPE=$(PARAM_S_REG_TYPE) + COMPILE_ARGS += -GM_REG_TYPE=$(PARAM_M_REG_TYPE) + + ifeq ($(WAVES), 1) + COMPILE_ARGS += --trace-fst + endif +endif + +include $(shell cocotb-config --makefiles)/Makefile.sim + +$(WRAPPER).v: ../../rtl/$(DUT)_wrap.py + $< -p $(PARAM_S_COUNT) $(PARAM_M_COUNT) + +iverilog_dump.v: + echo 'module iverilog_dump();' > $@ + echo 'initial begin' >> $@ + echo ' $$dumpfile("$(TOPLEVEL).fst");' >> $@ + echo ' $$dumpvars(0, $(TOPLEVEL));' >> $@ + echo 'end' >> $@ + echo 'endmodule' >> $@ + +clean:: + @rm -rf iverilog_dump.v + @rm -rf dump.fst $(TOPLEVEL).fst + @rm -rf *_wrap_*.v diff --git a/tb/axis_switch/test_axis_switch.py b/tb/axis_switch/test_axis_switch.py new file mode 100644 index 000000000..1bdceceec --- /dev/null +++ b/tb/axis_switch/test_axis_switch.py @@ -0,0 +1,351 @@ +#!/usr/bin/env python +""" + +Copyright (c) 2021 Alex Forencich + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +""" + +import itertools +import logging +import os +import random +import subprocess + +import cocotb_test.simulator +import pytest + +import cocotb +from cocotb.clock import Clock +from cocotb.triggers import RisingEdge, Event +from cocotb.regression import TestFactory + +from cocotbext.axi import AxiStreamBus, AxiStreamFrame, AxiStreamSource, AxiStreamSink + + +class TB(object): + def __init__(self, dut): + self.dut = dut + + s_count = len(dut.axis_switch_inst.s_axis_tvalid) + m_count = len(dut.axis_switch_inst.m_axis_tvalid) + + self.log = logging.getLogger("cocotb.tb") + self.log.setLevel(logging.DEBUG) + + cocotb.fork(Clock(dut.clk, 10, units="ns").start()) + + self.source = [AxiStreamSource(AxiStreamBus.from_prefix(dut, f"s{k:02d}_axis"), dut.clk, dut.rst) for k in range(s_count)] + self.sink = [AxiStreamSink(AxiStreamBus.from_prefix(dut, f"m{k:02d}_axis"), dut.clk, dut.rst) for k in range(m_count)] + + def set_idle_generator(self, generator=None): + if generator: + for source in self.source: + source.set_pause_generator(generator()) + + def set_backpressure_generator(self, generator=None): + if generator: + for sink in self.sink: + sink.set_pause_generator(generator()) + + async def reset(self): + self.dut.rst.setimmediatevalue(0) + await RisingEdge(self.dut.clk) + await RisingEdge(self.dut.clk) + self.dut.rst <= 1 + await RisingEdge(self.dut.clk) + await RisingEdge(self.dut.clk) + self.dut.rst <= 0 + await RisingEdge(self.dut.clk) + await RisingEdge(self.dut.clk) + + +async def run_test(dut, payload_lengths=None, payload_data=None, idle_inserter=None, backpressure_inserter=None, s=0, m=0): + + tb = TB(dut) + + id_count = 2**len(tb.source[s].bus.tid) + + cur_id = 1 + + await tb.reset() + + tb.set_idle_generator(idle_inserter) + tb.set_backpressure_generator(backpressure_inserter) + + test_frames = [] + + for test_data in [payload_data(x) for x in payload_lengths()]: + test_frame = AxiStreamFrame(test_data) + test_frame.tid = cur_id + test_frame.tdest = m + + test_frames.append(test_frame) + await tb.source[s].send(test_frame) + + cur_id = (cur_id + 1) % id_count + + for test_frame in test_frames: + rx_frame = await tb.sink[m].recv() + + assert rx_frame.tdata == test_frame.tdata + assert rx_frame.tid == test_frame.tid + assert rx_frame.tdest == test_frame.tdest + assert not rx_frame.tuser + + assert all(s.empty() for s in tb.sink) + + await RisingEdge(dut.clk) + await RisingEdge(dut.clk) + + +async def run_test_tuser_assert(dut, s=0, m=0): + + tb = TB(dut) + + await tb.reset() + + test_data = bytearray(itertools.islice(itertools.cycle(range(256)), 32)) + test_frame = AxiStreamFrame(test_data, tuser=1, tdest=m) + await tb.source[s].send(test_frame) + + rx_frame = await tb.sink[m].recv() + + assert rx_frame.tdata == test_data + assert rx_frame.tuser + + assert all(s.empty() for s in tb.sink) + + await RisingEdge(dut.clk) + await RisingEdge(dut.clk) + + +async def run_arb_test(dut): + + tb = TB(dut) + + byte_lanes = tb.source[0].byte_lanes + id_count = 2**len(tb.source[0].bus.tid) + + cur_id = 1 + + await tb.reset() + + test_frames = [] + + length = byte_lanes*16 + test_data = bytearray(itertools.islice(itertools.cycle(range(256)), length)) + + for k in range(5): + test_frame = AxiStreamFrame(test_data, tx_complete=Event()) + test_frame.tid = cur_id + test_frame.tdest = 0 + + src_ind = 0 + + if k == 0: + src_ind = 0 + elif k == 4: + await test_frames[1].tx_complete.wait() + for j in range(8): + await RisingEdge(dut.clk) + src_ind = 0 + else: + src_ind = 1 + + test_frames.append(test_frame) + await tb.source[src_ind].send(test_frame) + + cur_id = (cur_id + 1) % id_count + + for k in [0, 1, 2, 4, 3]: + test_frame = test_frames[k] + rx_frame = await tb.sink[0].recv() + + assert rx_frame.tdata == test_frame.tdata + assert rx_frame.tid == test_frame.tid + assert rx_frame.tdest == test_frame.tdest + assert not rx_frame.tuser + + assert all(s.empty() for s in tb.sink) + + await RisingEdge(dut.clk) + await RisingEdge(dut.clk) + + +async def run_stress_test(dut, idle_inserter=None, backpressure_inserter=None): + + tb = TB(dut) + + byte_lanes = tb.source[0].byte_lanes + id_count = 2**len(tb.source[0].bus.tid) + + cur_id = 1 + + await tb.reset() + + tb.set_idle_generator(idle_inserter) + tb.set_backpressure_generator(backpressure_inserter) + + test_frames = [[list() for y in tb.sink] for x in tb.source] + + for p in range(len(tb.source)): + for k in range(128): + length = random.randint(1, byte_lanes*16) + test_data = bytearray(itertools.islice(itertools.cycle(range(256)), length)) + test_frame = AxiStreamFrame(test_data) + test_frame.tid = cur_id + test_frame.tdest = random.randrange(len(tb.sink)) + + test_frames[p][test_frame.tdest].append(test_frame) + await tb.source[p].send(test_frame) + + cur_id = (cur_id + 1) % id_count + + for lst in test_frames: + while any(lst): + rx_frame = await tb.sink[[x for x in lst if x][0][0].tdest].recv() + + test_frame = None + + for lst_a in test_frames: + for lst_b in lst_a: + if lst_b and lst_b[0].tid == rx_frame.tid: + test_frame = lst_b.pop(0) + break + + assert test_frame is not None + + assert rx_frame.tdata == test_frame.tdata + assert rx_frame.tid == test_frame.tid + assert rx_frame.tdest == test_frame.tdest + assert not rx_frame.tuser + + assert all(s.empty() for s in tb.sink) + + await RisingEdge(dut.clk) + await RisingEdge(dut.clk) + + +def cycle_pause(): + return itertools.cycle([1, 1, 1, 0]) + + +def size_list(): + data_width = len(cocotb.top.s00_axis_tdata) + byte_width = data_width // 8 + return list(range(1, byte_width*4+1))+[512]+[1]*64 + + +def incrementing_payload(length): + return bytearray(itertools.islice(itertools.cycle(range(256)), length)) + + +if cocotb.SIM_NAME: + + s_count = len(cocotb.top.axis_switch_inst.s_axis_tvalid) + m_count = len(cocotb.top.axis_switch_inst.m_axis_tvalid) + + factory = TestFactory(run_test) + factory.add_option("payload_lengths", [size_list]) + factory.add_option("payload_data", [incrementing_payload]) + factory.add_option("idle_inserter", [None, cycle_pause]) + factory.add_option("backpressure_inserter", [None, cycle_pause]) + factory.add_option("s", range(min(s_count, 2))) + factory.add_option("m", range(min(m_count, 2))) + factory.generate_tests() + + for test in [run_test_tuser_assert]: + factory = TestFactory(test) + factory.add_option("s", range(min(s_count, 2))) + factory.add_option("m", range(min(m_count, 2))) + factory.generate_tests() + + if s_count > 1: + factory = TestFactory(run_arb_test) + factory.generate_tests() + + factory = TestFactory(run_stress_test) + factory.add_option("idle_inserter", [None, cycle_pause]) + factory.add_option("backpressure_inserter", [None, cycle_pause]) + factory.generate_tests() + + +# cocotb-test + +tests_dir = os.path.dirname(__file__) +rtl_dir = os.path.abspath(os.path.join(tests_dir, '..', '..', 'rtl')) + + +@pytest.mark.parametrize("data_width", [8, 16, 32]) +@pytest.mark.parametrize("m_count", [1, 4]) +@pytest.mark.parametrize("s_count", [1, 4]) +def test_axis_switch(request, s_count, m_count, data_width): + dut = "axis_switch" + wrapper = f"{dut}_wrap_{s_count}x{m_count}" + module = os.path.splitext(os.path.basename(__file__))[0] + toplevel = wrapper + + # generate wrapper + wrapper_file = os.path.join(tests_dir, f"{wrapper}.v") + if not os.path.exists(wrapper_file): + subprocess.Popen( + [os.path.join(rtl_dir, f"{dut}_wrap.py"), "-p", f"{s_count}", f"{m_count}"], + cwd=tests_dir + ).wait() + + verilog_sources = [ + wrapper_file, + os.path.join(rtl_dir, f"{dut}.v"), + os.path.join(rtl_dir, "axis_register.v"), + os.path.join(rtl_dir, "arbiter.v"), + os.path.join(rtl_dir, "priority_encoder.v"), + ] + + parameters = {} + + parameters['S_COUNT'] = s_count + parameters['M_COUNT'] = m_count + + parameters['DATA_WIDTH'] = data_width + parameters['KEEP_ENABLE'] = int(parameters['DATA_WIDTH'] > 8) + parameters['KEEP_WIDTH'] = parameters['DATA_WIDTH'] // 8 + parameters['ID_ENABLE'] = 1 + parameters['ID_WIDTH'] = 16 + parameters['DEST_WIDTH'] = 8 + parameters['USER_ENABLE'] = 1 + parameters['USER_WIDTH'] = 1 + parameters['S_REG_TYPE'] = 0 + parameters['M_REG_TYPE'] = 2 + + extra_env = {f'PARAM_{k}': str(v) for k, v in parameters.items()} + + sim_build = os.path.join(tests_dir, "sim_build", + request.node.name.replace('[', '-').replace(']', '')) + + cocotb_test.simulator.run( + python_search=[tests_dir], + verilog_sources=verilog_sources, + toplevel=toplevel, + module=module, + parameters=parameters, + sim_build=sim_build, + extra_env=extra_env, + ) From e32f65f563c8fb4fbc1db35c8277f5cbc54dba5c Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Sun, 30 May 2021 12:39:49 -0700 Subject: [PATCH 12/14] Update test durations --- .test_durations | 636 ++++++++++++++++++++++++++++-------------------- 1 file changed, 374 insertions(+), 262 deletions(-) diff --git a/.test_durations b/.test_durations index edcbacf3c..f3789db61 100644 --- a/.test_durations +++ b/.test_durations @@ -1,566 +1,678 @@ [ - [ - "tb/axis_adapter/test_axis_adapter.py::test_axis_register[32-16]", - 4.064560260856524 - ], - [ - "tb/axis_arb_mux/test_axis_arb_mux.py::test_axis_arb_mux[4-16]", - 13.143233641982079 - ], - [ - "tb/axis_adapter/test_axis_adapter.py::test_axis_register[8-8]", - 5.109369816957042 - ], - [ - "tb/axis_adapter/test_axis_adapter.py::test_axis_register[8-16]", - 5.058328598272055 - ], [ "tb/axis_adapter/test_axis_adapter.py::test_axis_register[16-16]", - 3.893145425245166 + 8.593190127052367 ], [ "tb/axis_adapter/test_axis_adapter.py::test_axis_register[16-32]", - 3.9831731799058616 + 12.195417289622128 ], [ - "tb/axis_arb_mux/test_axis_arb_mux.py::test_axis_arb_mux[1-8]", - 5.490476330043748 + "tb/axis_adapter/test_axis_adapter.py::test_axis_register[16-8]", + 9.789422770030797 ], [ - "tb/axis_adapter/test_axis_adapter.py::test_axis_register[32-8]", - 5.087842009961605 + "tb/axis_adapter/test_axis_adapter.py::test_axis_register[32-16]", + 12.671152506023645 ], [ "tb/axis_adapter/test_axis_adapter.py::test_axis_register[32-32]", - 3.063372714910656 + 7.9916584407910705 ], [ - "tb/axis_adapter/test_axis_adapter.py::test_axis_register[8-32]", - 5.046062843874097 + "tb/axis_adapter/test_axis_adapter.py::test_axis_register[32-8]", + 18.75230613257736 ], [ - "tb/axis_arb_mux/test_axis_arb_mux.py::test_axis_arb_mux[4-8]", - 19.940929262898862 + "tb/axis_adapter/test_axis_adapter.py::test_axis_register[8-16]", + 12.944865978322923 ], [ - "tb/axis_async_fifo/test_axis_async_fifo.py::test_axis_async_fifo[8-0]", - 10.152885030955076 + "tb/axis_adapter/test_axis_adapter.py::test_axis_register[8-32]", + 14.129353470169008 ], [ - "tb/axis_adapter/test_axis_adapter.py::test_axis_register[16-8]", - 5.021060193190351 + "tb/axis_adapter/test_axis_adapter.py::test_axis_register[8-8]", + 9.817764451727271 ], [ "tb/axis_arb_mux/test_axis_arb_mux.py::test_axis_arb_mux[1-16]", - 3.669280304107815 + 8.91946775931865 ], [ - "tb/axis_async_fifo/test_axis_async_fifo.py::test_axis_async_fifo[16-1]", - 9.14714803174138 + "tb/axis_arb_mux/test_axis_arb_mux.py::test_axis_arb_mux[1-32]", + 8.098858617246151 ], [ - "tb/axis_async_fifo/test_axis_async_fifo.py::test_axis_async_fifo[16-0]", - 6.992672564228997 + "tb/axis_arb_mux/test_axis_arb_mux.py::test_axis_arb_mux[1-8]", + 9.076799966394901 ], [ - "tb/axis_async_fifo/test_axis_async_fifo.py::test_axis_async_fifo[8-1]", - 11.191074956208467 + "tb/axis_arb_mux/test_axis_arb_mux.py::test_axis_arb_mux[4-16]", + 41.119202432222664 ], [ "tb/axis_arb_mux/test_axis_arb_mux.py::test_axis_arb_mux[4-32]", - 10.364595271181315 + 39.96406711637974 ], [ - "tb/axis_async_fifo/test_axis_async_fifo.py::test_axis_async_fifo[32-0]", - 5.5928368042223155 + "tb/axis_arb_mux/test_axis_arb_mux.py::test_axis_arb_mux[4-8]", + 48.189331891946495 ], [ - "tb/axis_arb_mux/test_axis_arb_mux.py::test_axis_arb_mux[1-32]", - 3.247817731462419 + "tb/axis_async_fifo/test_axis_async_fifo.py::test_axis_async_fifo[16-0]", + 11.827675406821072 ], [ - "tb/axis_async_fifo/test_axis_async_fifo.py::test_axis_async_fifo[64-0]", - 6.674111388158053 + "tb/axis_async_fifo/test_axis_async_fifo.py::test_axis_async_fifo[16-1]", + 16.27723410911858 ], [ - "tb/axis_async_fifo/test_axis_async_fifo.py::test_axis_async_fifo[32-1]", - 7.402053208090365 + "tb/axis_async_fifo/test_axis_async_fifo.py::test_axis_async_fifo[32-0]", + 12.823232500813901 ], [ - "tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py::test_axis_async_fifo_adapter[8-8-0]", - 10.20524234091863 + "tb/axis_async_fifo/test_axis_async_fifo.py::test_axis_async_fifo[32-1]", + 16.625567510724068 ], [ - "tb/axis_async_fifo/test_axis_async_fifo.py::test_axis_async_fifo[64-1]", - 7.729181434959173 + "tb/axis_async_fifo/test_axis_async_fifo.py::test_axis_async_fifo[64-0]", + 14.016773122362792 ], [ - "tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py::test_axis_async_fifo_adapter[8-16-0]", - 9.401650847867131 + "tb/axis_async_fifo/test_axis_async_fifo.py::test_axis_async_fifo[64-1]", + 13.324867684394121 ], [ - "tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py::test_axis_async_fifo_adapter[8-8-1]", - 12.24883275711909 + "tb/axis_async_fifo/test_axis_async_fifo.py::test_axis_async_fifo[8-0]", + 17.48489771410823 ], [ - "tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py::test_axis_async_fifo_adapter[16-8-1]", - 10.960868348134682 + "tb/axis_async_fifo/test_axis_async_fifo.py::test_axis_async_fifo[8-1]", + 20.536784620955586 ], [ "tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py::test_axis_async_fifo_adapter[16-16-0]", - 7.650945161934942 + 15.515931718982756 ], [ - "tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py::test_axis_async_fifo_adapter[8-32-0]", - 8.842617793940008 + "tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py::test_axis_async_fifo_adapter[16-16-1]", + 15.86473059374839 ], [ - "tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py::test_axis_async_fifo_adapter[8-32-1]", - 10.332504970021546 + "tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py::test_axis_async_fifo_adapter[16-32-0]", + 19.79045902378857 ], [ - "tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py::test_axis_async_fifo_adapter[8-16-1]", - 11.13730639917776 + "tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py::test_axis_async_fifo_adapter[16-32-1]", + 22.031130514107645 ], [ "tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py::test_axis_async_fifo_adapter[16-8-0]", - 10.321694103768095 + 23.1467945240438 ], [ - "tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py::test_axis_async_fifo_adapter[16-16-1]", - 8.53622887772508 + "tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py::test_axis_async_fifo_adapter[16-8-1]", + 24.25652244873345 ], [ - "tb/axis_broadcast/test_axis_broadcast.py::test_axis_broadcast[3-8]", - 6.011481063906103 + "tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py::test_axis_async_fifo_adapter[32-16-0]", + 21.167339676991105 ], [ - "tb/axis_broadcast/test_axis_broadcast.py::test_axis_broadcast[3-32]", - 4.004094589035958 + "tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py::test_axis_async_fifo_adapter[32-16-1]", + 15.328569454140961 ], [ "tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py::test_axis_async_fifo_adapter[32-32-0]", - 6.661400060867891 + 13.75000267289579 ], [ - "tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py::test_axis_async_fifo_adapter[16-32-1]", - 9.30316348792985 - ], - [ - "tb/axis_cobs_encode/test_axis_cobs_encode.py::test_axis_cobs_encode[0]", - 59.72865728009492 + "tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py::test_axis_async_fifo_adapter[32-32-1]", + 14.697162045165896 ], [ - "tb/axis_fifo/test_axis_fifo.py::test_axis_fifo[32-1]", - 5.509672118816525 + "tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py::test_axis_async_fifo_adapter[32-8-0]", + 34.25803263951093 ], [ - "tb/axis_fifo/test_axis_fifo.py::test_axis_fifo[8-0]", - 6.509261818835512 + "tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py::test_axis_async_fifo_adapter[32-8-1]", + 20.77494945563376 ], [ - "tb/axis_fifo/test_axis_fifo.py::test_axis_fifo[64-0]", - 5.037088224897161 + "tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py::test_axis_async_fifo_adapter[8-16-0]", + 22.107110468670726 ], [ - "tb/axis_fifo/test_axis_fifo.py::test_axis_fifo[32-0]", - 4.089887966867536 + "tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py::test_axis_async_fifo_adapter[8-16-1]", + 24.52229151222855 ], [ - "tb/axis_demux/test_axis_demux.py::test_axis_demux[4-16]", - 11.541036840062588 + "tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py::test_axis_async_fifo_adapter[8-32-0]", + 32.68651257175952 ], [ - "tb/axis_broadcast/test_axis_broadcast.py::test_axis_broadcast[2-8]", - 5.955809738021344 + "tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py::test_axis_async_fifo_adapter[8-32-1]", + 34.53164793737233 ], [ - "tb/axis_demux/test_axis_demux.py::test_axis_demux[4-8]", - 17.149116148008034 + "tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py::test_axis_async_fifo_adapter[8-8-0]", + 18.034708897583187 ], [ - "tb/axis_fifo/test_axis_fifo.py::test_axis_fifo[16-1]", - 6.595326299080625 + "tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py::test_axis_async_fifo_adapter[8-8-1]", + 21.166472426615655 ], [ - "tb/axis_cobs_decode/test_axis_cobs_decode.py::test_axis_cobs_decode", - 55.33392608910799 + "tb/axis_broadcast/test_axis_broadcast.py::test_axis_broadcast[1-16]", + 4.1349410535767674 ], [ - "tb/axis_fifo/test_axis_fifo.py::test_axis_fifo[8-1]", - 8.583656460046768 + "tb/axis_broadcast/test_axis_broadcast.py::test_axis_broadcast[1-32]", + 1.9841334708034992 ], [ - "tb/axis_broadcast/test_axis_broadcast.py::test_axis_broadcast[2-32]", - 1.9311450261157006 + "tb/axis_broadcast/test_axis_broadcast.py::test_axis_broadcast[1-8]", + 4.198510793969035 ], [ - "tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py::test_axis_async_fifo_adapter[16-32-0]", - 6.75402541924268 + "tb/axis_broadcast/test_axis_broadcast.py::test_axis_broadcast[2-16]", + 2.692502399906516 ], [ - "tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py::test_axis_async_fifo_adapter[32-8-0]", - 5.700722533976659 + "tb/axis_broadcast/test_axis_broadcast.py::test_axis_broadcast[2-32]", + 2.386414110660553 ], [ - "tb/axis_fifo/test_axis_fifo.py::test_axis_fifo[16-0]", - 5.485037375707179 + "tb/axis_broadcast/test_axis_broadcast.py::test_axis_broadcast[2-8]", + 4.363627223297954 ], [ - "tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py::test_axis_async_fifo_adapter[32-16-0]", - 7.350736285792664 + "tb/axis_broadcast/test_axis_broadcast.py::test_axis_broadcast[3-16]", + 3.1008117590099573 ], [ - "tb/axis_fifo/test_axis_fifo.py::test_axis_fifo[64-1]", - 5.567466985201463 + "tb/axis_broadcast/test_axis_broadcast.py::test_axis_broadcast[3-32]", + 2.8256580103188753 ], [ - "tb/axis_broadcast/test_axis_broadcast.py::test_axis_broadcast[1-32]", - 3.0928381660487503 + "tb/axis_broadcast/test_axis_broadcast.py::test_axis_broadcast[3-8]", + 4.709306005388498 ], [ - "tb/axis_broadcast/test_axis_broadcast.py::test_axis_broadcast[3-16]", - 4.969628504943103 + "tb/axis_cobs_decode/test_axis_cobs_decode.py::test_axis_cobs_decode", + 54.703362938947976 ], [ - "tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py::test_axis_async_fifo_adapter[32-8-1]", - 6.349259327631444 + "tb/axis_cobs_encode/test_axis_cobs_encode.py::test_axis_cobs_encode[0]", + 59.61654491070658 ], [ - "tb/axis_fifo_adapter/test_axis_fifo_adapter.py::test_axis_fifo_adapter[8-8-1]", - 8.99701732210815 + "tb/axis_cobs_encode/test_axis_cobs_encode.py::test_axis_cobs_encode[1]", + 58.38117606379092 ], [ - "tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py::test_axis_async_fifo_adapter[32-16-1]", - 9.235969598637894 + "tb/axis_demux/test_axis_demux.py::test_axis_demux[4-16]", + 9.495323976501822 ], [ "tb/axis_demux/test_axis_demux.py::test_axis_demux[4-32]", - 9.538748257094994 + 6.288495775312185 ], [ - "tb/axis_async_fifo_adapter/test_axis_async_fifo_adapter.py::test_axis_async_fifo_adapter[32-32-1]", - 7.745282106800005 + "tb/axis_demux/test_axis_demux.py::test_axis_demux[4-8]", + 18.37746755219996 ], [ - "tb/axis_fifo_adapter/test_axis_fifo_adapter.py::test_axis_fifo_adapter[8-16-1]", - 6.823330983985215 + "tb/axis_fifo/test_axis_fifo.py::test_axis_fifo[16-0]", + 10.393654933199286 ], [ - "tb/axis_fifo_adapter/test_axis_fifo_adapter.py::test_axis_fifo_adapter[8-8-0]", - 5.227903796825558 + "tb/axis_fifo/test_axis_fifo.py::test_axis_fifo[16-1]", + 10.415633418597281 ], [ - "tb/axis_broadcast/test_axis_broadcast.py::test_axis_broadcast[2-16]", - 4.625557336257771 + "tb/axis_fifo/test_axis_fifo.py::test_axis_fifo[32-0]", + 8.87678967602551 ], [ - "tb/axis_fifo_adapter/test_axis_fifo_adapter.py::test_axis_fifo_adapter[16-16-1]", - 4.071335948072374 + "tb/axis_fifo/test_axis_fifo.py::test_axis_fifo[32-1]", + 11.098749899305403 ], [ - "tb/axis_fifo_adapter/test_axis_fifo_adapter.py::test_axis_fifo_adapter[16-8-1]", - 4.733443915843964 + "tb/axis_fifo/test_axis_fifo.py::test_axis_fifo[64-0]", + 9.422987031750381 ], [ - "tb/axis_fifo_adapter/test_axis_fifo_adapter.py::test_axis_fifo_adapter[8-32-1]", - 5.415835375897586 + "tb/axis_fifo/test_axis_fifo.py::test_axis_fifo[64-1]", + 9.699089953675866 ], [ - "tb/axis_fifo_adapter/test_axis_fifo_adapter.py::test_axis_fifo_adapter[32-32-0]", - 4.996851528994739 + "tb/axis_fifo/test_axis_fifo.py::test_axis_fifo[8-0]", + 11.044142582453787 ], [ - "tb/axis_fifo_adapter/test_axis_fifo_adapter.py::test_axis_fifo_adapter[32-16-1]", - 6.541619814001024 + "tb/axis_fifo/test_axis_fifo.py::test_axis_fifo[8-1]", + 10.83289519045502 ], [ - "tb/axis_fifo_adapter/test_axis_fifo_adapter.py::test_axis_fifo_adapter[16-32-1]", - 7.052604428259656 + "tb/axis_fifo_adapter/test_axis_fifo_adapter.py::test_axis_fifo_adapter[16-16-0]", + 10.219957860186696 ], [ - "tb/axis_broadcast/test_axis_broadcast.py::test_axis_broadcast[1-8]", - 5.601683816872537 + "tb/axis_fifo_adapter/test_axis_fifo_adapter.py::test_axis_fifo_adapter[16-16-1]", + 10.486625554971397 ], [ "tb/axis_fifo_adapter/test_axis_fifo_adapter.py::test_axis_fifo_adapter[16-32-0]", - 5.533007082296535 + 14.431692690588534 + ], + [ + "tb/axis_fifo_adapter/test_axis_fifo_adapter.py::test_axis_fifo_adapter[16-32-1]", + 15.22019578423351 ], [ "tb/axis_fifo_adapter/test_axis_fifo_adapter.py::test_axis_fifo_adapter[16-8-0]", - 7.243967947084457 + 14.902987204492092 ], [ - "tb/axis_fifo_adapter/test_axis_fifo_adapter.py::test_axis_fifo_adapter[32-8-0]", - 7.279493370791897 + "tb/axis_fifo_adapter/test_axis_fifo_adapter.py::test_axis_fifo_adapter[16-8-1]", + 11.420198984444141 ], [ "tb/axis_fifo_adapter/test_axis_fifo_adapter.py::test_axis_fifo_adapter[32-16-0]", - 6.444722287822515 + 13.592619517818093 ], [ - "tb/axis_fifo_adapter/test_axis_fifo_adapter.py::test_axis_fifo_adapter[8-32-0]", - 5.101694668177515 + "tb/axis_fifo_adapter/test_axis_fifo_adapter.py::test_axis_fifo_adapter[32-16-1]", + 14.155559001490474 ], [ - "tb/axis_fifo_adapter/test_axis_fifo_adapter.py::test_axis_fifo_adapter[8-16-0]", - 7.083118926966563 + "tb/axis_fifo_adapter/test_axis_fifo_adapter.py::test_axis_fifo_adapter[32-32-0]", + 9.66715748142451 ], [ - "tb/axis_cobs_encode/test_axis_cobs_encode.py::test_axis_cobs_encode[1]", - 59.118370523210615 + "tb/axis_fifo_adapter/test_axis_fifo_adapter.py::test_axis_fifo_adapter[32-32-1]", + 9.999405917711556 ], [ - "tb/axis_fifo_adapter/test_axis_fifo_adapter.py::test_axis_fifo_adapter[16-16-0]", - 4.102237894199789 + "tb/axis_fifo_adapter/test_axis_fifo_adapter.py::test_axis_fifo_adapter[32-8-0]", + 22.81020149681717 ], [ - "tb/axis_frame_length_adjust/test_axis_frame_length_adjust.py::test_axis_frame_length_adjust[32]", - 5.109332735883072 + "tb/axis_fifo_adapter/test_axis_fifo_adapter.py::test_axis_fifo_adapter[32-8-1]", + 22.00941563770175 ], [ - "tb/axis_frame_length_adjust_fifo/test_axis_frame_length_adjust_fifo.py::test_axis_frame_length_adjust_fifo[8]", - 31.400041729211807 + "tb/axis_fifo_adapter/test_axis_fifo_adapter.py::test_axis_fifo_adapter[8-16-0]", + 15.273434751667082 ], [ - "tb/axis_frame_length_adjust/test_axis_frame_length_adjust.py::test_axis_frame_length_adjust[8]", - 6.68104299204424 + "tb/axis_fifo_adapter/test_axis_fifo_adapter.py::test_axis_fifo_adapter[8-16-1]", + 16.60779592487961 ], [ - "tb/axis_frame_length_adjust/test_axis_frame_length_adjust.py::test_axis_frame_length_adjust[16]", - 6.474900439847261 + "tb/axis_fifo_adapter/test_axis_fifo_adapter.py::test_axis_fifo_adapter[8-32-0]", + 22.687564965337515 ], [ - "tb/axis_fifo_adapter/test_axis_fifo_adapter.py::test_axis_fifo_adapter[32-32-1]", - 6.242845824919641 + "tb/axis_fifo_adapter/test_axis_fifo_adapter.py::test_axis_fifo_adapter[8-32-1]", + 23.706279216334224 ], [ - "tb/axis_fifo_adapter/test_axis_fifo_adapter.py::test_axis_fifo_adapter[32-8-1]", - 7.743526546051726 + "tb/axis_fifo_adapter/test_axis_fifo_adapter.py::test_axis_fifo_adapter[8-8-0]", + 11.400899667292833 ], [ - "tb/axis_broadcast/test_axis_broadcast.py::test_axis_broadcast[1-16]", - 3.705136342905462 + "tb/axis_fifo_adapter/test_axis_fifo_adapter.py::test_axis_fifo_adapter[8-8-1]", + 12.362589475698769 + ], + [ + "tb/axis_frame_length_adjust/test_axis_frame_length_adjust.py::test_axis_frame_length_adjust[16]", + 4.168933109380305 + ], + [ + "tb/axis_frame_length_adjust/test_axis_frame_length_adjust.py::test_axis_frame_length_adjust[32]", + 3.4525004364550114 + ], + [ + "tb/axis_frame_length_adjust/test_axis_frame_length_adjust.py::test_axis_frame_length_adjust[8]", + 6.410637116059661 ], [ "tb/axis_frame_length_adjust_fifo/test_axis_frame_length_adjust_fifo.py::test_axis_frame_length_adjust_fifo[16]", - 20.34973389096558 + 18.54528176225722 ], [ "tb/axis_frame_length_adjust_fifo/test_axis_frame_length_adjust_fifo.py::test_axis_frame_length_adjust_fifo[32]", - 16.08616164396517 + 14.18258341960609 + ], + [ + "tb/axis_frame_length_adjust_fifo/test_axis_frame_length_adjust_fifo.py::test_axis_frame_length_adjust_fifo[8]", + 29.039860404096544 ], [ "tb/axis_mux/test_axis_mux.py::test_axis_mux[1-16]", - 3.7994882098864764 + 2.7313873413950205 + ], + [ + "tb/axis_mux/test_axis_mux.py::test_axis_mux[1-32]", + 2.1904209554195404 ], [ "tb/axis_mux/test_axis_mux.py::test_axis_mux[1-8]", - 5.135501990094781 + 3.747754485346377 ], [ - "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[0-8-0]", - 5.485889535630122 + "tb/axis_mux/test_axis_mux.py::test_axis_mux[4-16]", + 11.27847404498607 + ], + [ + "tb/axis_mux/test_axis_mux.py::test_axis_mux[4-32]", + 8.642733175307512 ], [ "tb/axis_mux/test_axis_mux.py::test_axis_mux[4-8]", - 20.19369739596732 + 18.31573899462819 ], [ - "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[1-32-0]", - 1.561464497121051 + "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[0-16-0]", + 7.748892365954816 ], [ - "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[1-8-2]", - 5.337176482891664 + "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[0-16-1]", + 8.249635859392583 ], [ - "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[1-16-0]", - 2.4496163791045547 + "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[0-16-2]", + 7.861832721158862 + ], + [ + "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[0-32-0]", + 7.814906599000096 + ], + [ + "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[0-32-1]", + 7.478627904318273 + ], + [ + "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[0-32-2]", + 8.728103519417346 + ], + [ + "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[0-8-0]", + 8.562991634011269 + ], + [ + "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[0-8-1]", + 8.853606965392828 ], [ "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[0-8-2]", - 5.699582742061466 + 10.302599406801164 ], [ - "tb/axis_mux/test_axis_mux.py::test_axis_mux[4-16]", - 13.788990666391328 + "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[1-16-0]", + 8.787222282029688 ], [ "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[1-16-1]", - 2.0261589840520173 + 9.04017788078636 + ], + [ + "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[1-16-2]", + 8.097946026362479 + ], + [ + "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[1-32-0]", + 6.282582161016762 ], [ "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[1-32-1]", - 3.11552363820374 + 8.129383312538266 ], [ - "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[0-32-2]", - 3.1700994120910764 + "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[1-32-2]", + 7.848937609232962 + ], + [ + "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[1-8-0]", + 6.842636492103338 ], [ "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[1-8-1]", - 5.923924314090982 + 9.389978448860347 ], [ - "tb/axis_mux/test_axis_mux.py::test_axis_mux[4-32]", - 7.972323116846383 + "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[1-8-2]", + 9.679912436753511 + ], + [ + "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[2-16-0]", + 7.3867769334465265 + ], + [ + "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[2-16-1]", + 8.3051818581298 + ], + [ + "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[2-16-2]", + 8.126775786280632 + ], + [ + "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[2-32-0]", + 7.643013674765825 ], [ "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[2-32-1]", - 3.0416711198631674 + 8.875891353935003 ], [ "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[2-32-2]", - 3.31060864077881 + 8.881751327775419 ], [ - "tb/axis_rate_limit/test_axis_rate_limit.py::test_axis_rate_limit[8]", - 20.769642549101263 + "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[2-8-0]", + 9.265739167109132 ], [ - "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[2-16-1]", - 2.2487674469593912 + "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[2-8-1]", + 10.11152211111039 ], [ "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[2-8-2]", - 5.267716252012178 + 8.9882518267259 ], [ - "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[0-8-1]", - 4.380764984991401 + "tb/axis_ram_switch/test_axis_ram_switch.py::test_axis_ram_switch[1-1-32-32]", + 10.515457849018276 ], [ - "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[2-8-1]", - 5.923575797583908 + "tb/axis_ram_switch/test_axis_ram_switch.py::test_axis_ram_switch[1-1-32-8]", + 23.015697445720434 ], [ - "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[0-32-0]", - 3.125814629253 + "tb/axis_ram_switch/test_axis_ram_switch.py::test_axis_ram_switch[1-1-8-32]", + 23.339799378067255 ], [ - "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[0-16-1]", - 3.336507275234908 + "tb/axis_ram_switch/test_axis_ram_switch.py::test_axis_ram_switch[1-1-8-8]", + 13.376416123472154 ], [ - "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[1-16-2]", - 1.9632220172788948 + "tb/axis_ram_switch/test_axis_ram_switch.py::test_axis_ram_switch[1-4-32-32]", + 15.32683065906167 ], [ - "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[0-16-2]", - 3.883476712042466 + "tb/axis_ram_switch/test_axis_ram_switch.py::test_axis_ram_switch[1-4-32-8]", + 25.25002766493708 ], [ - "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[2-32-0]", - 3.093082787003368 + "tb/axis_ram_switch/test_axis_ram_switch.py::test_axis_ram_switch[1-4-8-32]", + 38.70766987465322 ], [ - "tb/axis_rate_limit/test_axis_rate_limit.py::test_axis_rate_limit[32]", - 10.130301585188136 + "tb/axis_ram_switch/test_axis_ram_switch.py::test_axis_ram_switch[1-4-8-8]", + 23.433873833157122 ], [ - "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[2-16-2]", - 4.012627676827833 + "tb/axis_ram_switch/test_axis_ram_switch.py::test_axis_ram_switch[4-1-32-32]", + 38.13711098767817 ], [ - "tb/axis_mux/test_axis_mux.py::test_axis_mux[1-32]", - 2.9808353721164167 + "tb/axis_ram_switch/test_axis_ram_switch.py::test_axis_ram_switch[4-1-32-8]", + 108.21325397957116 ], [ - "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[1-8-0]", - 5.803714094217867 + "tb/axis_ram_switch/test_axis_ram_switch.py::test_axis_ram_switch[4-1-8-32]", + 31.623636212199926 ], [ - "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[0-32-1]", - 3.003260609926656 + "tb/axis_ram_switch/test_axis_ram_switch.py::test_axis_ram_switch[4-1-8-8]", + 46.20649198163301 ], [ - "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[1-32-2]", - 3.2507454978767782 + "tb/axis_ram_switch/test_axis_ram_switch.py::test_axis_ram_switch[4-4-32-32]", + 36.73501186538488 ], [ - "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[2-16-0]", - 3.6894755298271775 + "tb/axis_ram_switch/test_axis_ram_switch.py::test_axis_ram_switch[4-4-32-8]", + 74.66561388224363 ], [ - "tb/axis_rate_limit/test_axis_rate_limit.py::test_axis_rate_limit[16]", - 8.963756704237312 + "tb/axis_ram_switch/test_axis_ram_switch.py::test_axis_ram_switch[4-4-8-32]", + 51.076979514211416 ], [ - "tb/axis_rate_limit/test_axis_rate_limit.py::test_axis_rate_limit[64]", - 10.402460905024782 + "tb/axis_ram_switch/test_axis_ram_switch.py::test_axis_ram_switch[4-4-8-8]", + 57.79113897960633 ], [ - "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[0-16-0]", - 3.8650066470727324 + "tb/axis_rate_limit/test_axis_rate_limit.py::test_axis_rate_limit[16]", + 11.168463669717312 ], [ - "tb/axis_pipeline_register/test_axis_pipeline_register.py::test_axis_pipeline_register[2-8-0]", - 5.027584437979385 + "tb/axis_rate_limit/test_axis_rate_limit.py::test_axis_rate_limit[32]", + 8.627638365142047 ], [ - "tb/axis_register/test_axis_register.py::test_axis_register[32-2]", - 1.9581461090128869 + "tb/axis_rate_limit/test_axis_rate_limit.py::test_axis_rate_limit[64]", + 8.261535592377186 ], [ - "tb/axis_srl_fifo/test_axis_srl_fifo.py::test_axis_srl_fifo[32]", - 3.736734739970416 + "tb/axis_rate_limit/test_axis_rate_limit.py::test_axis_rate_limit[8]", + 18.147929472848773 ], [ - "tb/axis_srl_fifo/test_axis_srl_fifo.py::test_axis_srl_fifo[16]", - 8.996261154068634 + "tb/axis_register/test_axis_register.py::test_axis_register[16-0]", + 7.894782732240856 ], [ "tb/axis_register/test_axis_register.py::test_axis_register[16-1]", - 2.9044135720469058 + 8.63187304791063 ], [ "tb/axis_register/test_axis_register.py::test_axis_register[16-2]", - 2.8243840648792684 + 7.384906925261021 + ], + [ + "tb/axis_register/test_axis_register.py::test_axis_register[32-0]", + 7.757337849587202 ], [ "tb/axis_register/test_axis_register.py::test_axis_register[32-1]", - 2.0222588209435344 + 8.349224615842104 ], [ - "tb/axis_register/test_axis_register.py::test_axis_register[16-0]", - 2.4645475880242884 + "tb/axis_register/test_axis_register.py::test_axis_register[32-2]", + 8.202552252449095 ], [ - "tb/axis_register/test_axis_register.py::test_axis_register[8-2]", - 3.2331926051992923 + "tb/axis_register/test_axis_register.py::test_axis_register[8-0]", + 9.517546870745718 ], [ "tb/axis_register/test_axis_register.py::test_axis_register[8-1]", - 3.5214195190928876 + 9.37106759659946 ], [ - "tb/axis_register/test_axis_register.py::test_axis_register[32-0]", - 1.7708753109909594 + "tb/axis_register/test_axis_register.py::test_axis_register[8-2]", + 8.858125889673829 ], [ - "tb/axis_register/test_axis_register.py::test_axis_register[8-0]", - 3.4010211310815066 + "tb/axis_srl_fifo/test_axis_srl_fifo.py::test_axis_srl_fifo[16]", + 21.84353820141405 ], [ - "tb/axis_srl_fifo/test_axis_srl_fifo.py::test_axis_srl_fifo[8]", - 6.477508798940107 + "tb/axis_srl_fifo/test_axis_srl_fifo.py::test_axis_srl_fifo[32]", + 19.996354782022536 ], [ - "tb/axis_srl_register/test_axis_srl_register.py::test_axis_srl_register[32]", - 1.7259511651936918 + "tb/axis_srl_fifo/test_axis_srl_fifo.py::test_axis_srl_fifo[64]", + 21.48448957223445 + ], + [ + "tb/axis_srl_fifo/test_axis_srl_fifo.py::test_axis_srl_fifo[8]", + 26.7858392810449 ], [ "tb/axis_srl_register/test_axis_srl_register.py::test_axis_srl_register[16]", - 2.1865312785375863 + 8.400416224263608 + ], + [ + "tb/axis_srl_register/test_axis_srl_register.py::test_axis_srl_register[32]", + 7.900802923366427 ], [ "tb/axis_srl_register/test_axis_srl_register.py::test_axis_srl_register[8]", - 3.358409102773294 + 8.795997133478522 ], [ - "tb/axis_srl_fifo/test_axis_srl_fifo.py::test_axis_srl_fifo[64]", - 5.105467068264261 + "tb/axis_switch/test_axis_switch.py::test_axis_switch[1-1-16]", + 8.356694316491485 + ], + [ + "tb/axis_switch/test_axis_switch.py::test_axis_switch[1-1-32]", + 7.599317821674049 + ], + [ + "tb/axis_switch/test_axis_switch.py::test_axis_switch[1-1-8]", + 9.621531581506133 + ], + [ + "tb/axis_switch/test_axis_switch.py::test_axis_switch[1-4-16]", + 13.667238024994731 + ], + [ + "tb/axis_switch/test_axis_switch.py::test_axis_switch[1-4-32]", + 13.290190611034632 + ], + [ + "tb/axis_switch/test_axis_switch.py::test_axis_switch[1-4-8]", + 16.950868975371122 + ], + [ + "tb/axis_switch/test_axis_switch.py::test_axis_switch[4-1-16]", + 33.594604125246406 + ], + [ + "tb/axis_switch/test_axis_switch.py::test_axis_switch[4-1-32]", + 33.071954203769565 + ], + [ + "tb/axis_switch/test_axis_switch.py::test_axis_switch[4-1-8]", + 36.24359125737101 + ], + [ + "tb/axis_switch/test_axis_switch.py::test_axis_switch[4-4-16]", + 33.63313777372241 + ], + [ + "tb/axis_switch/test_axis_switch.py::test_axis_switch[4-4-32]", + 22.27076547406614 + ], + [ + "tb/axis_switch/test_axis_switch.py::test_axis_switch[4-4-8]", + 39.87212748918682 ] ] \ No newline at end of file From 35793104477708f153cd09d0be47d500779fdbdf Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Mon, 31 May 2021 01:31:30 -0700 Subject: [PATCH 13/14] Clear active bit --- rtl/axis_ram_switch.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtl/axis_ram_switch.v b/rtl/axis_ram_switch.v index 343aac99d..57a22295a 100644 --- a/rtl/axis_ram_switch.v +++ b/rtl/axis_ram_switch.v @@ -769,7 +769,7 @@ generate if (cmd_table_finish_en) begin cmd_table_finish_ptr_reg <= cmd_table_finish_ptr_reg + 1; - cmd_table_active[cmd_table_finish_ptr_reg[CMD_ADDR_WIDTH-1:0]] <= 1'b1; + cmd_table_active[cmd_table_finish_ptr_reg[CMD_ADDR_WIDTH-1:0]] <= 1'b0; end if (rst) begin From 892ee84bff4ca38f20a2c5ef9be01fd4e8a223ba Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Mon, 31 May 2021 01:32:02 -0700 Subject: [PATCH 14/14] Delay command until write is acknowledged --- rtl/axis_ram_switch.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtl/axis_ram_switch.v b/rtl/axis_ram_switch.v index 57a22295a..f12cfaba8 100644 --- a/rtl/axis_ram_switch.v +++ b/rtl/axis_ram_switch.v @@ -691,7 +691,7 @@ generate // read cmd_valid_next = cmd_valid_reg & ~port_cmd_ready; - if (!cmd_valid_reg && cmd_table_active[cmd_table_read_ptr_reg[CMD_ADDR_WIDTH-1:0]] && cmd_table_read_ptr_reg != cmd_table_start_ptr_reg) begin + if (!cmd_valid_reg && cmd_table_active[cmd_table_read_ptr_reg[CMD_ADDR_WIDTH-1:0]] && cmd_table_read_ptr_reg != cmd_table_start_ptr_reg && (!ram_wr_en_reg || ram_wr_ack)) begin cmd_table_read_en = 1'b1; cmd_addr_next = cmd_table_addr_start[cmd_table_read_ptr_reg[CMD_ADDR_WIDTH-1:0]]; cmd_len_next = cmd_table_len[cmd_table_read_ptr_reg[CMD_ADDR_WIDTH-1:0]];