diff --git a/rtl/axis_frame_len.v b/rtl/axis_frame_len.v new file mode 100644 index 000000000..e4dfe6596 --- /dev/null +++ b/rtl/axis_frame_len.v @@ -0,0 +1,110 @@ +/* + +Copyright (c) 2019 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 frame length measurement + */ +module axis_frame_len # +( + parameter DATA_WIDTH = 64, + parameter KEEP_ENABLE = (DATA_WIDTH>8), + parameter KEEP_WIDTH = (DATA_WIDTH/8), + parameter LEN_WIDTH = 16 +) +( + input wire clk, + input wire rst, + + /* + * AXI monitor + */ + input wire [KEEP_WIDTH-1:0] monitor_axis_tkeep, + input wire monitor_axis_tvalid, + input wire monitor_axis_tready, + input wire monitor_axis_tlast, + + /* + * Status + */ + output wire [LEN_WIDTH-1:0] frame_len, + output wire frame_len_valid +); + +reg [LEN_WIDTH-1:0] frame_len_reg = 0, frame_len_next; +reg frame_len_valid_reg = 1'b0, frame_len_valid_next; +reg frame_reg = 1'b0, frame_next; + +assign frame_len = frame_len_reg; +assign frame_len_valid = frame_len_valid_reg; + +integer offset, i, bit_cnt; + +always @* begin + frame_len_next = frame_len_reg; + frame_len_valid_next = 1'b0; + frame_next = frame_reg; + + if (monitor_axis_tready && monitor_axis_tvalid) begin + // valid transfer cycle + + if (monitor_axis_tlast) begin + // end of frame + frame_len_valid_next = 1'b1; + frame_next = 1'b0; + end else if (!frame_reg) begin + // first word after end of frame + frame_len_next = 0; + frame_next = 1'b1; + end + + // increment frame length by number of words transferred + if (KEEP_ENABLE) begin + bit_cnt = 0; + for (i = 0; i <= KEEP_WIDTH; i = i + 1) begin + if (monitor_axis_tkeep == ({KEEP_WIDTH{1'b1}}) >> (KEEP_WIDTH-i)) bit_cnt = i; + end + frame_len_next = frame_len_next + bit_cnt; + end else begin + frame_len_next = frame_len_next + 1; + end + end +end + +always @(posedge clk) begin + if (rst) begin + frame_len_reg <= 0; + frame_len_valid_reg <= 0; + frame_reg <= 1'b0; + end else begin + frame_len_reg <= frame_len_next; + frame_len_valid_reg <= frame_len_valid_next; + frame_reg <= frame_next; + end +end + +endmodule diff --git a/tb/test_axis_frame_len_64.py b/tb/test_axis_frame_len_64.py new file mode 100755 index 000000000..229004749 --- /dev/null +++ b/tb/test_axis_frame_len_64.py @@ -0,0 +1,418 @@ +#!/usr/bin/env python +""" + +Copyright (c) 2019 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. + +""" + +from myhdl import * +import os + +import axis_ep + +module = 'axis_frame_len' +testbench = 'test_%s_64' % module + +srcs = [] + +srcs.append("../rtl/%s.v" % module) +srcs.append("%s.v" % testbench) + +src = ' '.join(srcs) + +build_cmd = "iverilog -o %s.vvp %s" % (testbench, src) + +def bench(): + + # Parameters + DATA_WIDTH = 64 + KEEP_ENABLE = (DATA_WIDTH>8) + KEEP_WIDTH = (DATA_WIDTH/8) + LEN_WIDTH = 16 + + # Inputs + clk = Signal(bool(0)) + rst = Signal(bool(0)) + current_test = Signal(intbv(0)[8:]) + + monitor_axis_tdata = Signal(intbv(0)[DATA_WIDTH:]) + monitor_axis_tkeep = Signal(intbv(1)[KEEP_WIDTH:]) + monitor_axis_tvalid = Signal(bool(0)) + monitor_axis_tready = Signal(bool(0)) + monitor_axis_tlast = Signal(bool(0)) + + # Outputs + frame_len = Signal(intbv(0)[LEN_WIDTH:]) + frame_len_valid = Signal(bool(0)) + + # sources and sinks + source_pause = Signal(bool(0)) + sink_pause = Signal(bool(0)) + + source = axis_ep.AXIStreamSource() + + source_logic = source.create_logic( + clk, + rst, + tdata=monitor_axis_tdata, + tkeep=monitor_axis_tkeep, + tvalid=monitor_axis_tvalid, + tready=monitor_axis_tready, + tlast=monitor_axis_tlast, + pause=source_pause, + name='source' + ) + + sink = axis_ep.AXIStreamSink() + + sink_logic = sink.create_logic( + clk, + rst, + tdata=monitor_axis_tdata, + tkeep=monitor_axis_tkeep, + tvalid=monitor_axis_tvalid, + tready=monitor_axis_tready, + tlast=monitor_axis_tlast, + pause=sink_pause, + name='sink' + ) + + frame_len_sink = axis_ep.AXIStreamSink() + + frame_len_sink_logic = frame_len_sink.create_logic( + clk, + rst, + tdata=frame_len, + tvalid=frame_len_valid, + name='frame_len_sink' + ) + + # DUT + if os.system(build_cmd): + raise Exception("Error running build command") + + dut = Cosimulation( + "vvp -m myhdl %s.vvp -lxt2" % testbench, + clk=clk, + rst=rst, + current_test=current_test, + + monitor_axis_tkeep=monitor_axis_tkeep, + monitor_axis_tvalid=monitor_axis_tvalid, + monitor_axis_tready=monitor_axis_tready, + monitor_axis_tlast=monitor_axis_tlast, + + frame_len=frame_len, + frame_len_valid=frame_len_valid + ) + + @always(delay(4)) + def clkgen(): + clk.next = not clk + + @instance + def check(): + yield delay(100) + yield clk.posedge + rst.next = 1 + yield clk.posedge + rst.next = 0 + yield clk.posedge + yield delay(100) + yield clk.posedge + + yield clk.posedge + print("test 1: test packet") + current_test.next = 1 + + test_frame = axis_ep.AXIStreamFrame( + b'\xDA\xD1\xD2\xD3\xD4\xD5' + + b'\x5A\x51\x52\x53\x54\x55' + + b'\x80\x00' + + b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10' + ) + + source.send(test_frame) + yield clk.posedge + + while monitor_axis_tvalid: + yield clk.posedge + + yield sink.wait() + f = sink.recv() + + yield frame_len_sink.wait() + l = frame_len_sink.recv() + + assert len(f.data) == l.data[0] + + yield delay(100) + + yield clk.posedge + print("test 4: longer packet") + current_test.next = 4 + + test_frame = axis_ep.AXIStreamFrame( + b'\xDA\xD1\xD2\xD3\xD4\xD5' + + b'\x5A\x51\x52\x53\x54\x55' + + b'\x80\x00' + + bytearray(range(256)) + ) + + source.send(test_frame) + yield clk.posedge + + while monitor_axis_tvalid: + yield clk.posedge + + yield sink.wait() + f = sink.recv() + + yield frame_len_sink.wait() + l = frame_len_sink.recv() + + assert len(f.data) == l.data[0] + + yield delay(100) + + yield clk.posedge + print("test 5: test packet with pauses") + current_test.next = 5 + + test_frame = axis_ep.AXIStreamFrame( + b'\xDA\xD1\xD2\xD3\xD4\xD5' + + b'\x5A\x51\x52\x53\x54\x55' + + b'\x80\x00' + + bytearray(range(256)) + ) + + source.send(test_frame) + yield clk.posedge + + yield delay(64) + yield clk.posedge + source_pause.next = True + yield delay(32) + yield clk.posedge + source_pause.next = False + + yield delay(64) + yield clk.posedge + sink_pause.next = True + yield delay(32) + yield clk.posedge + sink_pause.next = False + + while monitor_axis_tvalid: + yield clk.posedge + + yield sink.wait() + f = sink.recv() + + yield frame_len_sink.wait() + l = frame_len_sink.recv() + + assert len(f.data) == l.data[0] + + yield delay(100) + + yield clk.posedge + print("test 6: back-to-back packets") + current_test.next = 6 + + test_frame1 = axis_ep.AXIStreamFrame( + b'\xDA\xD1\xD2\xD3\xD4\xD5' + + b'\x5A\x51\x52\x53\x54\x55' + + b'\x80\x00' + + b'\x01\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10' + ) + test_frame2 = axis_ep.AXIStreamFrame( + b'\xDA\xD1\xD2\xD3\xD4\xD5' + + b'\x5A\x51\x52\x53\x54\x55' + + b'\x80\x00' + + b'\x02\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10' + ) + + source.send(test_frame1) + source.send(test_frame2) + yield clk.posedge + + while monitor_axis_tvalid: + yield clk.posedge + + yield sink.wait() + f = sink.recv() + + yield frame_len_sink.wait() + l = frame_len_sink.recv() + + assert len(f.data) == l.data[0] + + yield sink.wait() + f = sink.recv() + + yield frame_len_sink.wait() + l = frame_len_sink.recv() + + assert len(f.data) == l.data[0] + + yield delay(100) + + yield clk.posedge + print("test 7: alternate pause source") + current_test.next = 7 + + test_frame1 = axis_ep.AXIStreamFrame( + b'\xDA\xD1\xD2\xD3\xD4\xD5' + + b'\x5A\x51\x52\x53\x54\x55' + + b'\x80\x00' + + b'\x01\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10' + ) + test_frame2 = axis_ep.AXIStreamFrame( + b'\xDA\xD1\xD2\xD3\xD4\xD5' + + b'\x5A\x51\x52\x53\x54\x55' + + b'\x80\x00' + + b'\x02\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10' + ) + + source.send(test_frame1) + source.send(test_frame2) + yield clk.posedge + + while monitor_axis_tvalid: + source_pause.next = True + yield clk.posedge + yield clk.posedge + yield clk.posedge + source_pause.next = False + yield clk.posedge + + yield sink.wait() + f = sink.recv() + + yield frame_len_sink.wait() + l = frame_len_sink.recv() + + assert len(f.data) == l.data[0] + + yield sink.wait() + f = sink.recv() + + yield frame_len_sink.wait() + l = frame_len_sink.recv() + + assert len(f.data) == l.data[0] + + yield delay(100) + + yield clk.posedge + print("test 8: alternate pause sink") + current_test.next = 8 + + test_frame1 = axis_ep.AXIStreamFrame( + b'\xDA\xD1\xD2\xD3\xD4\xD5' + + b'\x5A\x51\x52\x53\x54\x55' + + b'\x80\x00' + + b'\x01\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10' + ) + test_frame2 = axis_ep.AXIStreamFrame( + b'\xDA\xD1\xD2\xD3\xD4\xD5' + + b'\x5A\x51\x52\x53\x54\x55' + + b'\x80\x00' + + b'\x02\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10' + ) + + source.send(test_frame1) + source.send(test_frame2) + yield clk.posedge + + while monitor_axis_tvalid: + sink_pause.next = True + yield clk.posedge + yield clk.posedge + yield clk.posedge + sink_pause.next = False + yield clk.posedge + + yield sink.wait() + f = sink.recv() + + yield frame_len_sink.wait() + l = frame_len_sink.recv() + + assert len(f.data) == l.data[0] + + yield sink.wait() + f = sink.recv() + + yield frame_len_sink.wait() + l = frame_len_sink.recv() + + assert len(f.data) == l.data[0] + + yield delay(100) + + yield clk.posedge + print("test 9: various length packets") + current_test.next = 9 + + lens = [32, 48, 96, 128, 256] + test_frame = [] + + for i in lens: + test_frame.append(axis_ep.AXIStreamFrame( + b'\xDA\xD1\xD2\xD3\xD4\xD5' + + b'\x5A\x51\x52\x53\x54\x55' + + b'\x80\x00' + + bytearray(range(i))) + ) + + for f in test_frame: + source.send(f) + yield clk.posedge + + while monitor_axis_tvalid: + yield clk.posedge + + for i in lens: + yield sink.wait() + f = sink.recv() + + yield frame_len_sink.wait() + l = frame_len_sink.recv() + + assert len(f.data) == l.data[0] + + yield delay(100) + + raise StopSimulation + + return instances() + +def test_bench(): + os.chdir(os.path.dirname(os.path.abspath(__file__))) + sim = Simulation(bench()) + sim.run() + +if __name__ == '__main__': + print("Running test...") + test_bench() + diff --git a/tb/test_axis_frame_len_64.v b/tb/test_axis_frame_len_64.v new file mode 100644 index 000000000..ec4dadf01 --- /dev/null +++ b/tb/test_axis_frame_len_64.v @@ -0,0 +1,94 @@ +/* + +Copyright (c) 2019 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 + +/* + * Testbench for axis_frame_len + */ +module test_axis_frame_len_64; + +// Parameters +parameter DATA_WIDTH = 64; +parameter KEEP_ENABLE = (DATA_WIDTH>8); +parameter KEEP_WIDTH = (DATA_WIDTH/8); +parameter LEN_WIDTH = 16; + +// Inputs +reg clk = 0; +reg rst = 0; +reg [7:0] current_test = 0; + +reg [KEEP_WIDTH-1:0] monitor_axis_tkeep = 0; +reg monitor_axis_tvalid = 0; +reg monitor_axis_tready = 0; +reg monitor_axis_tlast = 0; + +// Outputs +wire [LEN_WIDTH-1:0] frame_len; +wire frame_len_valid; + +initial begin + // myhdl integration + $from_myhdl( + clk, + rst, + current_test, + monitor_axis_tkeep, + monitor_axis_tvalid, + monitor_axis_tready, + monitor_axis_tlast + ); + $to_myhdl( + frame_len, + frame_len_valid + ); + + // dump file + $dumpfile("test_axis_frame_len_64.lxt"); + $dumpvars(0, test_axis_frame_len_64); +end + +axis_frame_len #( + .DATA_WIDTH(DATA_WIDTH), + .KEEP_ENABLE(KEEP_ENABLE), + .KEEP_WIDTH(KEEP_WIDTH), + .LEN_WIDTH(LEN_WIDTH) +) +UUT ( + .clk(clk), + .rst(rst), + // AXI monitor + .monitor_axis_tkeep(monitor_axis_tkeep), + .monitor_axis_tvalid(monitor_axis_tvalid), + .monitor_axis_tready(monitor_axis_tready), + .monitor_axis_tlast(monitor_axis_tlast), + // Status + .frame_len(frame_len), + .frame_len_valid(frame_len_valid) +); + +endmodule diff --git a/tb/test_axis_frame_len_8.py b/tb/test_axis_frame_len_8.py new file mode 100755 index 000000000..9bca5f310 --- /dev/null +++ b/tb/test_axis_frame_len_8.py @@ -0,0 +1,420 @@ +#!/usr/bin/env python +""" + +Copyright (c) 2019 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. + +""" + +from myhdl import * +import os + +import axis_ep + +module = 'axis_frame_len' +testbench = 'test_%s_8' % module + +srcs = [] + +srcs.append("../rtl/%s.v" % module) +srcs.append("%s.v" % testbench) + +src = ' '.join(srcs) + +build_cmd = "iverilog -o %s.vvp %s" % (testbench, src) + +def bench(): + + # Parameters + DATA_WIDTH = 8 + KEEP_ENABLE = (DATA_WIDTH>8) + KEEP_WIDTH = (DATA_WIDTH/8) + LEN_WIDTH = 16 + + # Inputs + clk = Signal(bool(0)) + rst = Signal(bool(0)) + current_test = Signal(intbv(0)[8:]) + + monitor_axis_tdata = Signal(intbv(0)[DATA_WIDTH:]) + monitor_axis_tkeep = Signal(intbv(1)[KEEP_WIDTH:]) + monitor_axis_tvalid = Signal(bool(0)) + monitor_axis_tready = Signal(bool(0)) + monitor_axis_tlast = Signal(bool(0)) + + # Outputs + frame_len = Signal(intbv(0)[LEN_WIDTH:]) + frame_len_valid = Signal(bool(0)) + + # sources and sinks + source_pause = Signal(bool(0)) + sink_pause = Signal(bool(0)) + + source = axis_ep.AXIStreamSource() + + source_logic = source.create_logic( + clk, + rst, + tdata=monitor_axis_tdata, + tkeep=monitor_axis_tkeep, + tvalid=monitor_axis_tvalid, + tready=monitor_axis_tready, + tlast=monitor_axis_tlast, + pause=source_pause, + name='source' + ) + + sink = axis_ep.AXIStreamSink() + + sink_logic = sink.create_logic( + clk, + rst, + tdata=monitor_axis_tdata, + tkeep=monitor_axis_tkeep, + tvalid=monitor_axis_tvalid, + tready=monitor_axis_tready, + tlast=monitor_axis_tlast, + pause=sink_pause, + name='sink' + ) + + frame_len_sink = axis_ep.AXIStreamSink() + + frame_len_sink_logic = frame_len_sink.create_logic( + clk, + rst, + tdata=frame_len, + tvalid=frame_len_valid, + name='frame_len_sink' + ) + + # DUT + if os.system(build_cmd): + raise Exception("Error running build command") + + dut = Cosimulation( + "vvp -m myhdl %s.vvp -lxt2" % testbench, + clk=clk, + rst=rst, + current_test=current_test, + + monitor_axis_tkeep=monitor_axis_tkeep, + monitor_axis_tvalid=monitor_axis_tvalid, + monitor_axis_tready=monitor_axis_tready, + monitor_axis_tlast=monitor_axis_tlast, + + frame_len=frame_len, + frame_len_valid=frame_len_valid + ) + + @always(delay(4)) + def clkgen(): + clk.next = not clk + + @instance + def check(): + yield delay(100) + yield clk.posedge + rst.next = 1 + yield clk.posedge + rst.next = 0 + yield clk.posedge + yield delay(100) + yield clk.posedge + + yield clk.posedge + print("test 1: test packet") + current_test.next = 1 + + test_frame = axis_ep.AXIStreamFrame( + b'\xDA\xD1\xD2\xD3\xD4\xD5' + + b'\x5A\x51\x52\x53\x54\x55' + + b'\x80\x00' + + b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10' + ) + + source.send(test_frame) + yield clk.posedge + + while monitor_axis_tvalid: + yield clk.posedge + + yield sink.wait() + f = sink.recv() + + yield frame_len_sink.wait() + l = frame_len_sink.recv() + + assert len(f.data) == l.data[0] + + yield delay(100) + + yield clk.posedge + print("test 4: longer packet") + current_test.next = 4 + + test_frame = axis_ep.AXIStreamFrame( + b'\xDA\xD1\xD2\xD3\xD4\xD5' + + b'\x5A\x51\x52\x53\x54\x55' + + b'\x80\x00' + + bytearray(range(256)) + ) + + source.send(test_frame) + yield clk.posedge + + while monitor_axis_tvalid: + yield clk.posedge + + yield sink.wait() + f = sink.recv() + + yield frame_len_sink.wait() + l = frame_len_sink.recv() + + assert len(f.data) == l.data[0] + + yield delay(100) + + yield clk.posedge + print("test 5: test packet with pauses") + current_test.next = 5 + + test_frame = axis_ep.AXIStreamFrame( + b'\xDA\xD1\xD2\xD3\xD4\xD5' + + b'\x5A\x51\x52\x53\x54\x55' + + b'\x80\x00' + + bytearray(range(256)) + ) + + source.send(test_frame) + yield clk.posedge + + yield delay(64) + yield clk.posedge + source_pause.next = True + yield delay(32) + yield clk.posedge + source_pause.next = False + + yield delay(64) + yield clk.posedge + sink_pause.next = True + yield delay(32) + yield clk.posedge + sink_pause.next = False + + while monitor_axis_tvalid: + yield clk.posedge + + yield sink.wait() + f = sink.recv() + + yield frame_len_sink.wait() + l = frame_len_sink.recv() + + assert len(f.data) == l.data[0] + + yield delay(100) + + yield clk.posedge + print("test 6: back-to-back packets") + current_test.next = 6 + + test_frame1 = axis_ep.AXIStreamFrame( + b'\xDA\xD1\xD2\xD3\xD4\xD5' + + b'\x5A\x51\x52\x53\x54\x55' + + b'\x80\x00' + + b'\x01\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10' + ) + test_frame2 = axis_ep.AXIStreamFrame( + b'\xDA\xD1\xD2\xD3\xD4\xD5' + + b'\x5A\x51\x52\x53\x54\x55' + + b'\x80\x00' + + b'\x02\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10' + ) + + source.send(test_frame1) + source.send(test_frame2) + yield clk.posedge + + while monitor_axis_tvalid: + yield clk.posedge + + yield sink.wait() + f = sink.recv() + + yield frame_len_sink.wait() + l = frame_len_sink.recv() + + assert len(f.data) == l.data[0] + + yield sink.wait() + f = sink.recv() + + yield frame_len_sink.wait() + l = frame_len_sink.recv() + + assert len(f.data) == l.data[0] + + yield delay(100) + + yield clk.posedge + print("test 7: alternate pause source") + current_test.next = 7 + + test_frame1 = axis_ep.AXIStreamFrame( + b'\xDA\xD1\xD2\xD3\xD4\xD5' + + b'\x5A\x51\x52\x53\x54\x55' + + b'\x80\x00' + + b'\x01\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10' + ) + test_frame2 = axis_ep.AXIStreamFrame( + b'\xDA\xD1\xD2\xD3\xD4\xD5' + + b'\x5A\x51\x52\x53\x54\x55' + + b'\x80\x00' + + b'\x02\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10' + ) + + source.send(test_frame1) + source.send(test_frame2) + yield clk.posedge + + while monitor_axis_tvalid: + yield clk.posedge + yield clk.posedge + source_pause.next = False + yield clk.posedge + source_pause.next = True + yield clk.posedge + + source_pause.next = False + + yield sink.wait() + f = sink.recv() + + yield frame_len_sink.wait() + l = frame_len_sink.recv() + + assert len(f.data) == l.data[0] + + yield sink.wait() + f = sink.recv() + + yield frame_len_sink.wait() + l = frame_len_sink.recv() + + assert len(f.data) == l.data[0] + + yield delay(100) + + yield clk.posedge + print("test 8: alternate pause sink") + current_test.next = 8 + + test_frame1 = axis_ep.AXIStreamFrame( + b'\xDA\xD1\xD2\xD3\xD4\xD5' + + b'\x5A\x51\x52\x53\x54\x55' + + b'\x80\x00' + + b'\x01\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10' + ) + test_frame2 = axis_ep.AXIStreamFrame( + b'\xDA\xD1\xD2\xD3\xD4\xD5' + + b'\x5A\x51\x52\x53\x54\x55' + + b'\x80\x00' + + b'\x02\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10' + ) + + source.send(test_frame1) + source.send(test_frame2) + yield clk.posedge + + while monitor_axis_tvalid: + sink_pause.next = True + yield clk.posedge + yield clk.posedge + yield clk.posedge + sink_pause.next = False + yield clk.posedge + + yield sink.wait() + f = sink.recv() + + yield frame_len_sink.wait() + l = frame_len_sink.recv() + + assert len(f.data) == l.data[0] + + yield sink.wait() + f = sink.recv() + + yield frame_len_sink.wait() + l = frame_len_sink.recv() + + assert len(f.data) == l.data[0] + + yield delay(100) + + yield clk.posedge + print("test 9: various length packets") + current_test.next = 9 + + lens = [32, 48, 96, 128, 256] + test_frame = [] + + for i in lens: + test_frame.append(axis_ep.AXIStreamFrame( + b'\xDA\xD1\xD2\xD3\xD4\xD5' + + b'\x5A\x51\x52\x53\x54\x55' + + b'\x80\x00' + + bytearray(range(i))) + ) + + for f in test_frame: + source.send(f) + yield clk.posedge + + while monitor_axis_tvalid: + yield clk.posedge + + for i in lens: + yield sink.wait() + f = sink.recv() + + yield frame_len_sink.wait() + l = frame_len_sink.recv() + + assert len(f.data) == l.data[0] + + yield delay(100) + + raise StopSimulation + + return instances() + +def test_bench(): + os.chdir(os.path.dirname(os.path.abspath(__file__))) + sim = Simulation(bench()) + sim.run() + +if __name__ == '__main__': + print("Running test...") + test_bench() + diff --git a/tb/test_axis_frame_len_8.v b/tb/test_axis_frame_len_8.v new file mode 100644 index 000000000..0f40aa8e2 --- /dev/null +++ b/tb/test_axis_frame_len_8.v @@ -0,0 +1,94 @@ +/* + +Copyright (c) 2019 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 + +/* + * Testbench for axis_frame_len + */ +module test_axis_frame_len_8; + +// Parameters +parameter DATA_WIDTH = 8; +parameter KEEP_ENABLE = (DATA_WIDTH>8); +parameter KEEP_WIDTH = (DATA_WIDTH/8); +parameter LEN_WIDTH = 16; + +// Inputs +reg clk = 0; +reg rst = 0; +reg [7:0] current_test = 0; + +reg [KEEP_WIDTH-1:0] monitor_axis_tkeep = 0; +reg monitor_axis_tvalid = 0; +reg monitor_axis_tready = 0; +reg monitor_axis_tlast = 0; + +// Outputs +wire [LEN_WIDTH-1:0] frame_len; +wire frame_len_valid; + +initial begin + // myhdl integration + $from_myhdl( + clk, + rst, + current_test, + monitor_axis_tkeep, + monitor_axis_tvalid, + monitor_axis_tready, + monitor_axis_tlast + ); + $to_myhdl( + frame_len, + frame_len_valid + ); + + // dump file + $dumpfile("test_axis_frame_len_8.lxt"); + $dumpvars(0, test_axis_frame_len_8); +end + +axis_frame_len #( + .DATA_WIDTH(DATA_WIDTH), + .KEEP_ENABLE(KEEP_ENABLE), + .KEEP_WIDTH(KEEP_WIDTH), + .LEN_WIDTH(LEN_WIDTH) +) +UUT ( + .clk(clk), + .rst(rst), + // AXI monitor + .monitor_axis_tkeep(monitor_axis_tkeep), + .monitor_axis_tvalid(monitor_axis_tvalid), + .monitor_axis_tready(monitor_axis_tready), + .monitor_axis_tlast(monitor_axis_tlast), + // Status + .frame_len(frame_len), + .frame_len_valid(frame_len_valid) +); + +endmodule