diff --git a/lib/axis/rtl/axis_async_fifo.v b/lib/axis/rtl/axis_async_fifo.v index 659b2698d..d1b9fb4a4 100644 --- a/lib/axis/rtl/axis_async_fifo.v +++ b/lib/axis/rtl/axis_async_fifo.v @@ -302,7 +302,7 @@ always @* begin wr_ptr_cur_gray_next = wr_ptr_cur_next ^ (wr_ptr_cur_next >> 1); if (s_axis_tlast) begin // end of frame - if (DROP_BAD_FRAME && (USER_BAD_FRAME_MASK & s_axis_tuser == USER_BAD_FRAME_VALUE)) begin + if (DROP_BAD_FRAME && USER_BAD_FRAME_MASK & ~(s_axis_tuser ^ USER_BAD_FRAME_VALUE)) begin // bad packet, reset write pointer wr_ptr_cur_next = wr_ptr_reg; wr_ptr_cur_gray_next = wr_ptr_cur_next ^ (wr_ptr_cur_next >> 1); diff --git a/lib/axis/rtl/axis_async_fifo_adapter.v b/lib/axis/rtl/axis_async_fifo_adapter.v new file mode 100644 index 000000000..d8e626096 --- /dev/null +++ b/lib/axis/rtl/axis_async_fifo_adapter.v @@ -0,0 +1,321 @@ +/* + +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 asynchronous FIFO with width converter + */ +module axis_async_fifo_adapter # +( + parameter ADDR_WIDTH = 12, + parameter S_DATA_WIDTH = 8, + parameter S_KEEP_ENABLE = (S_DATA_WIDTH>8), + parameter S_KEEP_WIDTH = (S_DATA_WIDTH/8), + parameter M_DATA_WIDTH = 8, + parameter M_KEEP_ENABLE = (M_DATA_WIDTH>8), + parameter M_KEEP_WIDTH = (M_DATA_WIDTH/8), + parameter ID_ENABLE = 0, + parameter ID_WIDTH = 8, + parameter DEST_ENABLE = 0, + parameter DEST_WIDTH = 8, + parameter USER_ENABLE = 1, + parameter USER_WIDTH = 1, + parameter FRAME_FIFO = 0, + parameter USER_BAD_FRAME_VALUE = 1'b1, + parameter USER_BAD_FRAME_MASK = 1'b1, + parameter DROP_BAD_FRAME = 0, + parameter DROP_WHEN_FULL = 0 +) +( + /* + * AXI input + */ + input wire s_clk, + input wire s_rst, + input wire [S_DATA_WIDTH-1:0] s_axis_tdata, + input wire [S_KEEP_WIDTH-1:0] s_axis_tkeep, + input wire s_axis_tvalid, + output wire s_axis_tready, + input wire s_axis_tlast, + input wire [ID_WIDTH-1:0] s_axis_tid, + input wire [DEST_WIDTH-1:0] s_axis_tdest, + input wire [USER_WIDTH-1:0] s_axis_tuser, + + /* + * AXI output + */ + input wire m_clk, + input wire m_rst, + output wire [M_DATA_WIDTH-1:0] m_axis_tdata, + output wire [M_KEEP_WIDTH-1:0] m_axis_tkeep, + output wire m_axis_tvalid, + input wire m_axis_tready, + output wire m_axis_tlast, + output wire [ID_WIDTH-1:0] m_axis_tid, + output wire [DEST_WIDTH-1:0] m_axis_tdest, + output wire [USER_WIDTH-1:0] m_axis_tuser, + + /* + * Status + */ + output wire s_status_overflow, + output wire s_status_bad_frame, + output wire s_status_good_frame, + output wire m_status_overflow, + output wire m_status_bad_frame, + output wire m_status_good_frame +); + +// force keep width to 1 when disabled +parameter S_KEEP_WIDTH_INT = S_KEEP_ENABLE ? S_KEEP_WIDTH : 1; +parameter M_KEEP_WIDTH_INT = M_KEEP_ENABLE ? M_KEEP_WIDTH : 1; + +// bus word sizes (must be identical) +parameter S_DATA_WORD_SIZE = S_DATA_WIDTH / S_KEEP_WIDTH_INT; +parameter M_DATA_WORD_SIZE = M_DATA_WIDTH / M_KEEP_WIDTH_INT; +// output bus is wider +parameter EXPAND_BUS = M_KEEP_WIDTH_INT > S_KEEP_WIDTH_INT; +// total data and keep widths +parameter DATA_WIDTH = EXPAND_BUS ? M_DATA_WIDTH : S_DATA_WIDTH; +parameter KEEP_WIDTH = EXPAND_BUS ? M_KEEP_WIDTH_INT : S_KEEP_WIDTH_INT; + +// bus width assertions +initial begin + if (S_DATA_WORD_SIZE * S_KEEP_WIDTH_INT != S_DATA_WIDTH) begin + $error("Error: input data width not evenly divisble"); + $finish; + end + + if (M_DATA_WORD_SIZE * M_KEEP_WIDTH_INT != M_DATA_WIDTH) begin + $error("Error: output data width not evenly divisble"); + $finish; + end + + if (S_DATA_WORD_SIZE != M_DATA_WORD_SIZE) begin + $error("Error: word size mismatch"); + $finish; + end +end + +wire [DATA_WIDTH-1:0] pre_fifo_axis_tdata; +wire [KEEP_WIDTH-1:0] pre_fifo_axis_tkeep; +wire pre_fifo_axis_tvalid; +wire pre_fifo_axis_tready; +wire pre_fifo_axis_tlast; +wire [ID_WIDTH-1:0] pre_fifo_axis_tid; +wire [DEST_WIDTH-1:0] pre_fifo_axis_tdest; +wire [USER_WIDTH-1:0] pre_fifo_axis_tuser; + +wire [DATA_WIDTH-1:0] post_fifo_axis_tdata; +wire [KEEP_WIDTH-1:0] post_fifo_axis_tkeep; +wire post_fifo_axis_tvalid; +wire post_fifo_axis_tready; +wire post_fifo_axis_tlast; +wire [ID_WIDTH-1:0] post_fifo_axis_tid; +wire [DEST_WIDTH-1:0] post_fifo_axis_tdest; +wire [USER_WIDTH-1:0] post_fifo_axis_tuser; + +generate + +if (M_KEEP_WIDTH == S_KEEP_WIDTH) begin + + // same width, no adapter needed + + assign pre_fifo_axis_tdata = s_axis_tdata; + assign pre_fifo_axis_tkeep = s_axis_tkeep; + assign pre_fifo_axis_tvalid = s_axis_tvalid; + assign s_axis_tready = pre_fifo_axis_tready; + assign pre_fifo_axis_tlast = s_axis_tlast; + assign pre_fifo_axis_tid = s_axis_tid; + assign pre_fifo_axis_tdest = s_axis_tdest; + assign pre_fifo_axis_tuser = s_axis_tuser; + + assign m_axis_tdata = post_fifo_axis_tdata; + assign m_axis_tkeep = post_fifo_axis_tkeep; + assign m_axis_tvalid = post_fifo_axis_tvalid; + assign post_fifo_axis_tready = m_axis_tready; + assign m_axis_tlast = post_fifo_axis_tlast; + assign m_axis_tid = post_fifo_axis_tid; + assign m_axis_tdest = post_fifo_axis_tdest; + assign m_axis_tuser = post_fifo_axis_tuser; + + +end else if (EXPAND_BUS) begin + + // output wider, adapt width before FIFO + + axis_adapter #( + .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_ENABLE(DEST_ENABLE), + .DEST_WIDTH(DEST_WIDTH), + .USER_ENABLE(USER_ENABLE), + .USER_WIDTH(USER_WIDTH) + ) + adapter_inst ( + .clk(s_clk), + .rst(s_rst), + // AXI input + .s_axis_tdata(s_axis_tdata), + .s_axis_tkeep(s_axis_tkeep), + .s_axis_tvalid(s_axis_tvalid), + .s_axis_tready(s_axis_tready), + .s_axis_tlast(s_axis_tlast), + .s_axis_tid(s_axis_tid), + .s_axis_tdest(s_axis_tdest), + .s_axis_tuser(s_axis_tuser), + // AXI output + .m_axis_tdata(pre_fifo_axis_tdata), + .m_axis_tkeep(pre_fifo_axis_tkeep), + .m_axis_tvalid(pre_fifo_axis_tvalid), + .m_axis_tready(pre_fifo_axis_tready), + .m_axis_tlast(pre_fifo_axis_tlast), + .m_axis_tid(pre_fifo_axis_tid), + .m_axis_tdest(pre_fifo_axis_tdest), + .m_axis_tuser(pre_fifo_axis_tuser) + ); + + assign m_axis_tdata = post_fifo_axis_tdata; + assign m_axis_tkeep = post_fifo_axis_tkeep; + assign m_axis_tvalid = post_fifo_axis_tvalid; + assign post_fifo_axis_tready = m_axis_tready; + assign m_axis_tlast = post_fifo_axis_tlast; + assign m_axis_tid = post_fifo_axis_tid; + assign m_axis_tdest = post_fifo_axis_tdest; + assign m_axis_tuser = post_fifo_axis_tuser; + +end else begin + + // input wider, adapt width after FIFO + + assign pre_fifo_axis_tdata = s_axis_tdata; + assign pre_fifo_axis_tkeep = s_axis_tkeep; + assign pre_fifo_axis_tvalid = s_axis_tvalid; + assign s_axis_tready = pre_fifo_axis_tready; + assign pre_fifo_axis_tlast = s_axis_tlast; + assign pre_fifo_axis_tid = s_axis_tid; + assign pre_fifo_axis_tdest = s_axis_tdest; + assign pre_fifo_axis_tuser = s_axis_tuser; + + axis_adapter #( + .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_ENABLE(DEST_ENABLE), + .DEST_WIDTH(DEST_WIDTH), + .USER_ENABLE(USER_ENABLE), + .USER_WIDTH(USER_WIDTH) + ) + adapter_inst ( + .clk(m_clk), + .rst(m_rst), + // AXI input + .s_axis_tdata(post_fifo_axis_tdata), + .s_axis_tkeep(post_fifo_axis_tkeep), + .s_axis_tvalid(post_fifo_axis_tvalid), + .s_axis_tready(post_fifo_axis_tready), + .s_axis_tlast(post_fifo_axis_tlast), + .s_axis_tid(post_fifo_axis_tid), + .s_axis_tdest(post_fifo_axis_tdest), + .s_axis_tuser(post_fifo_axis_tuser), + // AXI output + .m_axis_tdata(m_axis_tdata), + .m_axis_tkeep(m_axis_tkeep), + .m_axis_tvalid(m_axis_tvalid), + .m_axis_tready(m_axis_tready), + .m_axis_tlast(m_axis_tlast), + .m_axis_tid(m_axis_tid), + .m_axis_tdest(m_axis_tdest), + .m_axis_tuser(m_axis_tuser) + ); + +end + +endgenerate + +axis_async_fifo #( + .ADDR_WIDTH(ADDR_WIDTH), + .DATA_WIDTH(DATA_WIDTH), + .KEEP_ENABLE(EXPAND_BUS ? M_KEEP_ENABLE : S_KEEP_ENABLE), + .KEEP_WIDTH(KEEP_WIDTH), + .LAST_ENABLE(1), + .ID_ENABLE(ID_ENABLE), + .ID_WIDTH(ID_WIDTH), + .DEST_ENABLE(DEST_ENABLE), + .DEST_WIDTH(DEST_WIDTH), + .USER_ENABLE(USER_ENABLE), + .USER_WIDTH(USER_WIDTH), + .FRAME_FIFO(FRAME_FIFO), + .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) +) +fifo_inst ( + // Common reset + .async_rst(s_rst | m_rst), + // AXI input + .s_clk(s_clk), + .s_axis_tdata(pre_fifo_axis_tdata), + .s_axis_tkeep(pre_fifo_axis_tkeep), + .s_axis_tvalid(pre_fifo_axis_tvalid), + .s_axis_tready(pre_fifo_axis_tready), + .s_axis_tlast(pre_fifo_axis_tlast), + .s_axis_tid(pre_fifo_axis_tid), + .s_axis_tdest(pre_fifo_axis_tdest), + .s_axis_tuser(pre_fifo_axis_tuser), + // AXI output + .m_clk(m_clk), + .m_axis_tdata(post_fifo_axis_tdata), + .m_axis_tkeep(post_fifo_axis_tkeep), + .m_axis_tvalid(post_fifo_axis_tvalid), + .m_axis_tready(post_fifo_axis_tready), + .m_axis_tlast(post_fifo_axis_tlast), + .m_axis_tid(post_fifo_axis_tid), + .m_axis_tdest(post_fifo_axis_tdest), + .m_axis_tuser(post_fifo_axis_tuser), + // Status + .s_status_overflow(s_status_overflow), + .s_status_bad_frame(s_status_bad_frame), + .s_status_good_frame(s_status_good_frame), + .m_status_overflow(m_status_overflow), + .m_status_bad_frame(m_status_bad_frame), + .m_status_good_frame(m_status_good_frame) +); + +endmodule diff --git a/lib/axis/rtl/axis_fifo.v b/lib/axis/rtl/axis_fifo.v index 83d89900d..d6329b1d9 100644 --- a/lib/axis/rtl/axis_fifo.v +++ b/lib/axis/rtl/axis_fifo.v @@ -207,7 +207,7 @@ always @* begin wr_ptr_cur_next = wr_ptr_cur_reg + 1; if (s_axis_tlast) begin // end of frame - if (DROP_BAD_FRAME && (USER_BAD_FRAME_MASK & s_axis_tuser == USER_BAD_FRAME_VALUE)) begin + if (DROP_BAD_FRAME && USER_BAD_FRAME_MASK & ~(s_axis_tuser ^ USER_BAD_FRAME_VALUE)) begin // bad packet, reset write pointer wr_ptr_cur_next = wr_ptr_reg; bad_frame_next = 1'b1; diff --git a/lib/axis/rtl/axis_fifo_adapter.v b/lib/axis/rtl/axis_fifo_adapter.v new file mode 100644 index 000000000..fac142c7d --- /dev/null +++ b/lib/axis/rtl/axis_fifo_adapter.v @@ -0,0 +1,311 @@ +/* + +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 FIFO with width converter + */ +module axis_fifo_adapter # +( + parameter ADDR_WIDTH = 12, + parameter S_DATA_WIDTH = 8, + parameter S_KEEP_ENABLE = (S_DATA_WIDTH>8), + parameter S_KEEP_WIDTH = (S_DATA_WIDTH/8), + parameter M_DATA_WIDTH = 8, + parameter M_KEEP_ENABLE = (M_DATA_WIDTH>8), + parameter M_KEEP_WIDTH = (M_DATA_WIDTH/8), + parameter ID_ENABLE = 0, + parameter ID_WIDTH = 8, + parameter DEST_ENABLE = 0, + parameter DEST_WIDTH = 8, + parameter USER_ENABLE = 1, + parameter USER_WIDTH = 1, + parameter FRAME_FIFO = 0, + parameter USER_BAD_FRAME_VALUE = 1'b1, + parameter USER_BAD_FRAME_MASK = 1'b1, + parameter DROP_BAD_FRAME = 0, + parameter DROP_WHEN_FULL = 0 +) +( + input wire clk, + input wire rst, + + /* + * AXI input + */ + input wire [S_DATA_WIDTH-1:0] s_axis_tdata, + input wire [S_KEEP_WIDTH-1:0] s_axis_tkeep, + input wire s_axis_tvalid, + output wire s_axis_tready, + input wire s_axis_tlast, + input wire [ID_WIDTH-1:0] s_axis_tid, + input wire [DEST_WIDTH-1:0] s_axis_tdest, + input wire [USER_WIDTH-1:0] s_axis_tuser, + + /* + * AXI output + */ + output wire [M_DATA_WIDTH-1:0] m_axis_tdata, + output wire [M_KEEP_WIDTH-1:0] m_axis_tkeep, + output wire m_axis_tvalid, + input wire m_axis_tready, + output wire m_axis_tlast, + output wire [ID_WIDTH-1:0] m_axis_tid, + output wire [DEST_WIDTH-1:0] m_axis_tdest, + output wire [USER_WIDTH-1:0] m_axis_tuser, + + /* + * Status + */ + output wire status_overflow, + output wire status_bad_frame, + output wire status_good_frame +); + +// force keep width to 1 when disabled +parameter S_KEEP_WIDTH_INT = S_KEEP_ENABLE ? S_KEEP_WIDTH : 1; +parameter M_KEEP_WIDTH_INT = M_KEEP_ENABLE ? M_KEEP_WIDTH : 1; + +// bus word sizes (must be identical) +parameter S_DATA_WORD_SIZE = S_DATA_WIDTH / S_KEEP_WIDTH_INT; +parameter M_DATA_WORD_SIZE = M_DATA_WIDTH / M_KEEP_WIDTH_INT; +// output bus is wider +parameter EXPAND_BUS = M_KEEP_WIDTH_INT > S_KEEP_WIDTH_INT; +// total data and keep widths +parameter DATA_WIDTH = EXPAND_BUS ? M_DATA_WIDTH : S_DATA_WIDTH; +parameter KEEP_WIDTH = EXPAND_BUS ? M_KEEP_WIDTH_INT : S_KEEP_WIDTH_INT; + +// bus width assertions +initial begin + if (S_DATA_WORD_SIZE * S_KEEP_WIDTH_INT != S_DATA_WIDTH) begin + $error("Error: input data width not evenly divisble"); + $finish; + end + + if (M_DATA_WORD_SIZE * M_KEEP_WIDTH_INT != M_DATA_WIDTH) begin + $error("Error: output data width not evenly divisble"); + $finish; + end + + if (S_DATA_WORD_SIZE != M_DATA_WORD_SIZE) begin + $error("Error: word size mismatch"); + $finish; + end +end + +wire [DATA_WIDTH-1:0] pre_fifo_axis_tdata; +wire [KEEP_WIDTH-1:0] pre_fifo_axis_tkeep; +wire pre_fifo_axis_tvalid; +wire pre_fifo_axis_tready; +wire pre_fifo_axis_tlast; +wire [ID_WIDTH-1:0] pre_fifo_axis_tid; +wire [DEST_WIDTH-1:0] pre_fifo_axis_tdest; +wire [USER_WIDTH-1:0] pre_fifo_axis_tuser; + +wire [DATA_WIDTH-1:0] post_fifo_axis_tdata; +wire [KEEP_WIDTH-1:0] post_fifo_axis_tkeep; +wire post_fifo_axis_tvalid; +wire post_fifo_axis_tready; +wire post_fifo_axis_tlast; +wire [ID_WIDTH-1:0] post_fifo_axis_tid; +wire [DEST_WIDTH-1:0] post_fifo_axis_tdest; +wire [USER_WIDTH-1:0] post_fifo_axis_tuser; + +generate + +if (M_KEEP_WIDTH_INT == S_KEEP_WIDTH_INT) begin + + // same width, no adapter needed + + assign pre_fifo_axis_tdata = s_axis_tdata; + assign pre_fifo_axis_tkeep = s_axis_tkeep; + assign pre_fifo_axis_tvalid = s_axis_tvalid; + assign s_axis_tready = pre_fifo_axis_tready; + assign pre_fifo_axis_tlast = s_axis_tlast; + assign pre_fifo_axis_tid = s_axis_tid; + assign pre_fifo_axis_tdest = s_axis_tdest; + assign pre_fifo_axis_tuser = s_axis_tuser; + + assign m_axis_tdata = post_fifo_axis_tdata; + assign m_axis_tkeep = post_fifo_axis_tkeep; + assign m_axis_tvalid = post_fifo_axis_tvalid; + assign post_fifo_axis_tready = m_axis_tready; + assign m_axis_tlast = post_fifo_axis_tlast; + assign m_axis_tid = post_fifo_axis_tid; + assign m_axis_tdest = post_fifo_axis_tdest; + assign m_axis_tuser = post_fifo_axis_tuser; + +end else if (EXPAND_BUS) begin + + // output wider, adapt width before FIFO + + axis_adapter #( + .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_ENABLE(DEST_ENABLE), + .DEST_WIDTH(DEST_WIDTH), + .USER_ENABLE(USER_ENABLE), + .USER_WIDTH(USER_WIDTH) + ) + adapter_inst ( + .clk(clk), + .rst(rst), + // AXI input + .s_axis_tdata(s_axis_tdata), + .s_axis_tkeep(s_axis_tkeep), + .s_axis_tvalid(s_axis_tvalid), + .s_axis_tready(s_axis_tready), + .s_axis_tlast(s_axis_tlast), + .s_axis_tid(s_axis_tid), + .s_axis_tdest(s_axis_tdest), + .s_axis_tuser(s_axis_tuser), + // AXI output + .m_axis_tdata(pre_fifo_axis_tdata), + .m_axis_tkeep(pre_fifo_axis_tkeep), + .m_axis_tvalid(pre_fifo_axis_tvalid), + .m_axis_tready(pre_fifo_axis_tready), + .m_axis_tlast(pre_fifo_axis_tlast), + .m_axis_tid(pre_fifo_axis_tid), + .m_axis_tdest(pre_fifo_axis_tdest), + .m_axis_tuser(pre_fifo_axis_tuser) + ); + + assign m_axis_tdata = post_fifo_axis_tdata; + assign m_axis_tkeep = post_fifo_axis_tkeep; + assign m_axis_tvalid = post_fifo_axis_tvalid; + assign post_fifo_axis_tready = m_axis_tready; + assign m_axis_tlast = post_fifo_axis_tlast; + assign m_axis_tid = post_fifo_axis_tid; + assign m_axis_tdest = post_fifo_axis_tdest; + assign m_axis_tuser = post_fifo_axis_tuser; + +end else begin + + // input wider, adapt width after FIFO + + assign pre_fifo_axis_tdata = s_axis_tdata; + assign pre_fifo_axis_tkeep = s_axis_tkeep; + assign pre_fifo_axis_tvalid = s_axis_tvalid; + assign s_axis_tready = pre_fifo_axis_tready; + assign pre_fifo_axis_tlast = s_axis_tlast; + assign pre_fifo_axis_tid = s_axis_tid; + assign pre_fifo_axis_tdest = s_axis_tdest; + assign pre_fifo_axis_tuser = s_axis_tuser; + + axis_adapter #( + .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_ENABLE(DEST_ENABLE), + .DEST_WIDTH(DEST_WIDTH), + .USER_ENABLE(USER_ENABLE), + .USER_WIDTH(USER_WIDTH) + ) + adapter_inst ( + .clk(clk), + .rst(rst), + // AXI input + .s_axis_tdata(post_fifo_axis_tdata), + .s_axis_tkeep(post_fifo_axis_tkeep), + .s_axis_tvalid(post_fifo_axis_tvalid), + .s_axis_tready(post_fifo_axis_tready), + .s_axis_tlast(post_fifo_axis_tlast), + .s_axis_tid(post_fifo_axis_tid), + .s_axis_tdest(post_fifo_axis_tdest), + .s_axis_tuser(post_fifo_axis_tuser), + // AXI output + .m_axis_tdata(m_axis_tdata), + .m_axis_tkeep(m_axis_tkeep), + .m_axis_tvalid(m_axis_tvalid), + .m_axis_tready(m_axis_tready), + .m_axis_tlast(m_axis_tlast), + .m_axis_tid(m_axis_tid), + .m_axis_tdest(m_axis_tdest), + .m_axis_tuser(m_axis_tuser) + ); + +end + +endgenerate + +axis_fifo #( + .ADDR_WIDTH(ADDR_WIDTH), + .DATA_WIDTH(DATA_WIDTH), + .KEEP_ENABLE(EXPAND_BUS ? M_KEEP_ENABLE : S_KEEP_ENABLE), + .KEEP_WIDTH(KEEP_WIDTH), + .LAST_ENABLE(1), + .ID_ENABLE(ID_ENABLE), + .ID_WIDTH(ID_WIDTH), + .DEST_ENABLE(DEST_ENABLE), + .DEST_WIDTH(DEST_WIDTH), + .USER_ENABLE(USER_ENABLE), + .USER_WIDTH(USER_WIDTH), + .FRAME_FIFO(FRAME_FIFO), + .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) +) +fifo_inst ( + .clk(clk), + .rst(rst), + // AXI input + .s_axis_tdata(pre_fifo_axis_tdata), + .s_axis_tkeep(pre_fifo_axis_tkeep), + .s_axis_tvalid(pre_fifo_axis_tvalid), + .s_axis_tready(pre_fifo_axis_tready), + .s_axis_tlast(pre_fifo_axis_tlast), + .s_axis_tid(pre_fifo_axis_tid), + .s_axis_tdest(pre_fifo_axis_tdest), + .s_axis_tuser(pre_fifo_axis_tuser), + // AXI output + .m_axis_tdata(post_fifo_axis_tdata), + .m_axis_tkeep(post_fifo_axis_tkeep), + .m_axis_tvalid(post_fifo_axis_tvalid), + .m_axis_tready(post_fifo_axis_tready), + .m_axis_tlast(post_fifo_axis_tlast), + .m_axis_tid(post_fifo_axis_tid), + .m_axis_tdest(post_fifo_axis_tdest), + .m_axis_tuser(post_fifo_axis_tuser), + // Status + .status_overflow(status_overflow), + .status_bad_frame(status_bad_frame), + .status_good_frame(status_good_frame) +); + +endmodule diff --git a/lib/axis/tb/test_axis_adapter_64_8.py b/lib/axis/tb/test_axis_adapter_64_8.py index bd51eca7e..7c1b7b48d 100755 --- a/lib/axis/tb/test_axis_adapter_64_8.py +++ b/lib/axis/tb/test_axis_adapter_64_8.py @@ -192,9 +192,6 @@ def check(): 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' + bytearray(range(payload_len)), id=1, dest=1, @@ -221,17 +218,11 @@ def check(): current_test.next = 2 test_frame1 = axis_ep.AXIStreamFrame( - b'\xDA\xD1\xD2\xD3\xD4\xD5' + - b'\x5A\x51\x52\x53\x54\x55' + - b'\x80\x00' + bytearray(range(payload_len)), id=2, dest=1, ) test_frame2 = axis_ep.AXIStreamFrame( - b'\xDA\xD1\xD2\xD3\xD4\xD5' + - b'\x5A\x51\x52\x53\x54\x55' + - b'\x80\x00' + bytearray(range(payload_len)), id=2, dest=2, @@ -264,18 +255,12 @@ def check(): current_test.next = 3 test_frame1 = axis_ep.AXIStreamFrame( - b'\xDA\xD1\xD2\xD3\xD4\xD5' + - b'\x5A\x51\x52\x53\x54\x55' + - b'\x80\x00' + bytearray(range(payload_len)), id=3, dest=1, last_cycle_user=1 ) test_frame2 = axis_ep.AXIStreamFrame( - b'\xDA\xD1\xD2\xD3\xD4\xD5' + - b'\x5A\x51\x52\x53\x54\x55' + - b'\x80\x00' + bytearray(range(payload_len)), id=3, dest=2, diff --git a/lib/axis/tb/test_axis_adapter_8_64.py b/lib/axis/tb/test_axis_adapter_8_64.py index 4acafae6a..43c2a46e0 100755 --- a/lib/axis/tb/test_axis_adapter_8_64.py +++ b/lib/axis/tb/test_axis_adapter_8_64.py @@ -192,9 +192,6 @@ def check(): 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' + bytearray(range(payload_len)), id=1, dest=1, @@ -221,17 +218,11 @@ def check(): current_test.next = 2 test_frame1 = axis_ep.AXIStreamFrame( - b'\xDA\xD1\xD2\xD3\xD4\xD5' + - b'\x5A\x51\x52\x53\x54\x55' + - b'\x80\x00' + bytearray(range(payload_len)), id=2, dest=1, ) test_frame2 = axis_ep.AXIStreamFrame( - b'\xDA\xD1\xD2\xD3\xD4\xD5' + - b'\x5A\x51\x52\x53\x54\x55' + - b'\x80\x00' + bytearray(range(payload_len)), id=2, dest=2, @@ -264,18 +255,12 @@ def check(): current_test.next = 3 test_frame1 = axis_ep.AXIStreamFrame( - b'\xDA\xD1\xD2\xD3\xD4\xD5' + - b'\x5A\x51\x52\x53\x54\x55' + - b'\x80\x00' + bytearray(range(payload_len)), id=3, dest=1, last_cycle_user=1 ) test_frame2 = axis_ep.AXIStreamFrame( - b'\xDA\xD1\xD2\xD3\xD4\xD5' + - b'\x5A\x51\x52\x53\x54\x55' + - b'\x80\x00' + bytearray(range(payload_len)), id=3, dest=2, diff --git a/lib/axis/tb/test_axis_async_fifo_adapter_64_8.py b/lib/axis/tb/test_axis_async_fifo_adapter_64_8.py new file mode 100755 index 000000000..9f1cca6a7 --- /dev/null +++ b/lib/axis/tb/test_axis_async_fifo_adapter_64_8.py @@ -0,0 +1,324 @@ +#!/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_async_fifo_adapter' +testbench = 'test_%s_64_8' % module + +srcs = [] + +srcs.append("../rtl/%s.v" % module) +srcs.append("../rtl/axis_adapter.v") +srcs.append("../rtl/axis_async_fifo.v") +srcs.append("%s.v" % testbench) + +src = ' '.join(srcs) + +build_cmd = "iverilog -o %s.vvp %s" % (testbench, src) + +def bench(): + + # Parameters + ADDR_WIDTH = 2 + S_DATA_WIDTH = 64 + S_KEEP_ENABLE = (S_DATA_WIDTH>8) + S_KEEP_WIDTH = (S_DATA_WIDTH/8) + M_DATA_WIDTH = 8 + M_KEEP_ENABLE = (M_DATA_WIDTH>8) + M_KEEP_WIDTH = (M_DATA_WIDTH/8) + ID_ENABLE = 1 + ID_WIDTH = 8 + DEST_ENABLE = 1 + DEST_WIDTH = 8 + USER_ENABLE = 1 + USER_WIDTH = 1 + FRAME_FIFO = 0 + USER_BAD_FRAME_VALUE = 1 + USER_BAD_FRAME_MASK = 1 + DROP_BAD_FRAME = 0 + DROP_WHEN_FULL = 0 + + # Inputs + s_clk = Signal(bool(0)) + s_rst = Signal(bool(0)) + m_clk = Signal(bool(0)) + m_rst = Signal(bool(0)) + current_test = Signal(intbv(0)[8:]) + + s_axis_tdata = Signal(intbv(0)[S_DATA_WIDTH:]) + s_axis_tkeep = Signal(intbv(1)[S_KEEP_WIDTH:]) + s_axis_tvalid = Signal(bool(0)) + s_axis_tlast = Signal(bool(0)) + s_axis_tid = Signal(intbv(0)[ID_WIDTH:]) + s_axis_tdest = Signal(intbv(0)[DEST_WIDTH:]) + s_axis_tuser = Signal(intbv(0)[USER_WIDTH:]) + m_axis_tready = Signal(bool(0)) + + # Outputs + s_axis_tready = Signal(bool(0)) + m_axis_tdata = Signal(intbv(0)[M_DATA_WIDTH:]) + m_axis_tkeep = Signal(intbv(1)[M_KEEP_WIDTH:]) + m_axis_tvalid = Signal(bool(0)) + m_axis_tlast = Signal(bool(0)) + m_axis_tid = Signal(intbv(0)[ID_WIDTH:]) + m_axis_tdest = Signal(intbv(0)[DEST_WIDTH:]) + m_axis_tuser = Signal(intbv(0)[USER_WIDTH:]) + + # sources and sinks + source_pause = Signal(bool(0)) + sink_pause = Signal(bool(0)) + + source = axis_ep.AXIStreamSource() + + source_logic = source.create_logic( + s_clk, + s_rst, + tdata=s_axis_tdata, + tkeep=s_axis_tkeep, + tvalid=s_axis_tvalid, + tready=s_axis_tready, + tlast=s_axis_tlast, + tid=s_axis_tid, + tdest=s_axis_tdest, + tuser=s_axis_tuser, + pause=source_pause, + name='source' + ) + + sink = axis_ep.AXIStreamSink() + + sink_logic = sink.create_logic( + m_clk, + m_rst, + tdata=m_axis_tdata, + tkeep=m_axis_tkeep, + tvalid=m_axis_tvalid, + tready=m_axis_tready, + tlast=m_axis_tlast, + tid=m_axis_tid, + tdest=m_axis_tdest, + tuser=m_axis_tuser, + pause=sink_pause, + name='sink' + ) + + # DUT + if os.system(build_cmd): + raise Exception("Error running build command") + + dut = Cosimulation( + "vvp -m myhdl %s.vvp -lxt2" % testbench, + s_clk=s_clk, + s_rst=s_rst, + m_clk=m_clk, + m_rst=m_rst, + current_test=current_test, + + s_axis_tdata=s_axis_tdata, + s_axis_tkeep=s_axis_tkeep, + s_axis_tvalid=s_axis_tvalid, + s_axis_tready=s_axis_tready, + s_axis_tlast=s_axis_tlast, + s_axis_tid=s_axis_tid, + s_axis_tdest=s_axis_tdest, + s_axis_tuser=s_axis_tuser, + + m_axis_tdata=m_axis_tdata, + m_axis_tkeep=m_axis_tkeep, + m_axis_tvalid=m_axis_tvalid, + m_axis_tready=m_axis_tready, + m_axis_tlast=m_axis_tlast, + m_axis_tid=m_axis_tid, + m_axis_tdest=m_axis_tdest, + m_axis_tuser=m_axis_tuser + ) + + @always(delay(4)) + def s_clkgen(): + s_clk.next = not s_clk + + @always(delay(5)) + def m_clkgen(): + m_clk.next = not m_clk + + def wait_normal(): + while s_axis_tvalid or m_axis_tvalid: + yield s_clk.posedge + + def wait_pause_source(): + while s_axis_tvalid or m_axis_tvalid: + yield s_clk.posedge + yield s_clk.posedge + source_pause.next = False + yield s_clk.posedge + source_pause.next = True + yield s_clk.posedge + + source_pause.next = False + + def wait_pause_sink(): + while s_axis_tvalid or m_axis_tvalid: + sink_pause.next = True + yield s_clk.posedge + yield s_clk.posedge + yield s_clk.posedge + sink_pause.next = False + yield s_clk.posedge + + @instance + def check(): + yield delay(100) + yield s_clk.posedge + s_rst.next = 1 + m_rst.next = 1 + yield s_clk.posedge + yield s_clk.posedge + yield s_clk.posedge + s_rst.next = 0 + m_rst.next = 0 + yield s_clk.posedge + yield delay(100) + yield s_clk.posedge + + for payload_len in range(1,18): + yield s_clk.posedge + print("test 1: test packet, length %d" % payload_len) + current_test.next = 1 + + test_frame = axis_ep.AXIStreamFrame( + bytearray(range(payload_len)), + id=1, + dest=1, + ) + + for wait in wait_normal, wait_pause_source, wait_pause_sink: + source.send(test_frame) + yield s_clk.posedge + yield s_clk.posedge + + yield wait() + + yield sink.wait() + rx_frame = sink.recv() + + assert rx_frame == test_frame + + assert sink.empty() + + yield delay(100) + + yield s_clk.posedge + print("test 2: back-to-back packets, length %d" % payload_len) + current_test.next = 2 + + test_frame1 = axis_ep.AXIStreamFrame( + bytearray(range(payload_len)), + id=2, + dest=1, + ) + test_frame2 = axis_ep.AXIStreamFrame( + bytearray(range(payload_len)), + id=2, + dest=2, + ) + + for wait in wait_normal, wait_pause_source, wait_pause_sink: + source.send(test_frame1) + source.send(test_frame2) + yield s_clk.posedge + yield s_clk.posedge + + yield wait() + + yield sink.wait() + rx_frame = sink.recv() + + assert rx_frame == test_frame1 + + yield sink.wait() + rx_frame = sink.recv() + + assert rx_frame == test_frame2 + + assert sink.empty() + + yield delay(100) + + yield s_clk.posedge + print("test 3: tuser assert, length %d" % payload_len) + current_test.next = 3 + + test_frame1 = axis_ep.AXIStreamFrame( + bytearray(range(payload_len)), + id=3, + dest=1, + last_cycle_user=1 + ) + test_frame2 = axis_ep.AXIStreamFrame( + bytearray(range(payload_len)), + id=3, + dest=2, + ) + + for wait in wait_normal, wait_pause_source, wait_pause_sink: + source.send(test_frame1) + source.send(test_frame2) + yield s_clk.posedge + yield s_clk.posedge + + yield wait() + + yield sink.wait() + rx_frame = sink.recv() + + assert rx_frame == test_frame1 + assert rx_frame.last_cycle_user + + yield sink.wait() + rx_frame = sink.recv() + + assert rx_frame == test_frame2 + + assert sink.empty() + + 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/lib/axis/tb/test_axis_async_fifo_adapter_64_8.v b/lib/axis/tb/test_axis_async_fifo_adapter_64_8.v new file mode 100644 index 000000000..22e206694 --- /dev/null +++ b/lib/axis/tb/test_axis_async_fifo_adapter_64_8.v @@ -0,0 +1,165 @@ +/* + +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_async_fifo_adapter + */ +module test_axis_async_fifo_adapter_64_8; + +// Parameters +parameter ADDR_WIDTH = 2; +parameter S_DATA_WIDTH = 64; +parameter S_KEEP_ENABLE = (S_DATA_WIDTH>8); +parameter S_KEEP_WIDTH = (S_DATA_WIDTH/8); +parameter M_DATA_WIDTH = 8; +parameter M_KEEP_ENABLE = (M_DATA_WIDTH>8); +parameter M_KEEP_WIDTH = (M_DATA_WIDTH/8); +parameter ID_ENABLE = 1; +parameter ID_WIDTH = 8; +parameter DEST_ENABLE = 1; +parameter DEST_WIDTH = 8; +parameter USER_ENABLE = 1; +parameter USER_WIDTH = 1; +parameter FRAME_FIFO = 0; +parameter USER_BAD_FRAME_VALUE = 1'b1; +parameter USER_BAD_FRAME_MASK = 1'b1; +parameter DROP_BAD_FRAME = 0; +parameter DROP_WHEN_FULL = 0; + +// Inputs +reg s_clk = 0; +reg s_rst = 0; +reg m_clk = 0; +reg m_rst = 0; +reg [7:0] current_test = 0; + +reg [S_DATA_WIDTH-1:0] s_axis_tdata = 0; +reg [S_KEEP_WIDTH-1:0] s_axis_tkeep = 0; +reg s_axis_tvalid = 0; +reg s_axis_tlast = 0; +reg [ID_WIDTH-1:0] s_axis_tid = 0; +reg [DEST_WIDTH-1:0] s_axis_tdest = 0; +reg [USER_WIDTH-1:0] s_axis_tuser = 0; +reg m_axis_tready = 0; + +// Outputs +wire s_axis_tready; +wire [M_DATA_WIDTH-1:0] m_axis_tdata; +wire [M_KEEP_WIDTH-1:0] m_axis_tkeep; +wire m_axis_tvalid; +wire m_axis_tlast; +wire [ID_WIDTH-1:0] m_axis_tid; +wire [DEST_WIDTH-1:0] m_axis_tdest; +wire [USER_WIDTH-1:0] m_axis_tuser; + +initial begin + // myhdl integration + $from_myhdl( + s_clk, + s_rst, + m_clk, + m_rst, + current_test, + s_axis_tdata, + s_axis_tkeep, + s_axis_tvalid, + s_axis_tlast, + s_axis_tid, + s_axis_tdest, + s_axis_tuser, + m_axis_tready + ); + $to_myhdl( + s_axis_tready, + m_axis_tdata, + m_axis_tkeep, + m_axis_tvalid, + m_axis_tlast, + m_axis_tid, + m_axis_tdest, + m_axis_tuser + ); + + // dump file + $dumpfile("test_axis_async_fifo_adapter_64_8.lxt"); + $dumpvars(0, test_axis_async_fifo_adapter_64_8); +end + +axis_async_fifo_adapter #( + .ADDR_WIDTH(ADDR_WIDTH), + .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_ENABLE(DEST_ENABLE), + .DEST_WIDTH(DEST_WIDTH), + .USER_ENABLE(USER_ENABLE), + .USER_WIDTH(USER_WIDTH), + .FRAME_FIFO(FRAME_FIFO), + .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) +) +UUT ( + // AXI input + .s_clk(s_clk), + .s_rst(s_rst), + .s_axis_tdata(s_axis_tdata), + .s_axis_tkeep(s_axis_tkeep), + .s_axis_tvalid(s_axis_tvalid), + .s_axis_tready(s_axis_tready), + .s_axis_tlast(s_axis_tlast), + .s_axis_tid(s_axis_tid), + .s_axis_tdest(s_axis_tdest), + .s_axis_tuser(s_axis_tuser), + // AXI output + .m_clk(m_clk), + .m_rst(m_rst), + .m_axis_tdata(m_axis_tdata), + .m_axis_tkeep(m_axis_tkeep), + .m_axis_tvalid(m_axis_tvalid), + .m_axis_tready(m_axis_tready), + .m_axis_tlast(m_axis_tlast), + .m_axis_tid(m_axis_tid), + .m_axis_tdest(m_axis_tdest), + .m_axis_tuser(m_axis_tuser), + // Status + .s_status_overflow(), + .s_status_bad_frame(), + .s_status_good_frame(), + .m_status_overflow(), + .m_status_bad_frame(), + .m_status_good_frame() +); + +endmodule diff --git a/lib/axis/tb/test_axis_async_fifo_adapter_8_64.py b/lib/axis/tb/test_axis_async_fifo_adapter_8_64.py new file mode 100755 index 000000000..d04ab1312 --- /dev/null +++ b/lib/axis/tb/test_axis_async_fifo_adapter_8_64.py @@ -0,0 +1,324 @@ +#!/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_async_fifo_adapter' +testbench = 'test_%s_8_64' % module + +srcs = [] + +srcs.append("../rtl/%s.v" % module) +srcs.append("../rtl/axis_adapter.v") +srcs.append("../rtl/axis_async_fifo.v") +srcs.append("%s.v" % testbench) + +src = ' '.join(srcs) + +build_cmd = "iverilog -o %s.vvp %s" % (testbench, src) + +def bench(): + + # Parameters + ADDR_WIDTH = 2 + S_DATA_WIDTH = 8 + S_KEEP_ENABLE = (S_DATA_WIDTH>8) + S_KEEP_WIDTH = (S_DATA_WIDTH/8) + M_DATA_WIDTH = 64 + M_KEEP_ENABLE = (M_DATA_WIDTH>8) + M_KEEP_WIDTH = (M_DATA_WIDTH/8) + ID_ENABLE = 1 + ID_WIDTH = 8 + DEST_ENABLE = 1 + DEST_WIDTH = 8 + USER_ENABLE = 1 + USER_WIDTH = 1 + FRAME_FIFO = 0 + USER_BAD_FRAME_VALUE = 1 + USER_BAD_FRAME_MASK = 1 + DROP_BAD_FRAME = 0 + DROP_WHEN_FULL = 0 + + # Inputs + s_clk = Signal(bool(0)) + s_rst = Signal(bool(0)) + m_clk = Signal(bool(0)) + m_rst = Signal(bool(0)) + current_test = Signal(intbv(0)[8:]) + + s_axis_tdata = Signal(intbv(0)[S_DATA_WIDTH:]) + s_axis_tkeep = Signal(intbv(1)[S_KEEP_WIDTH:]) + s_axis_tvalid = Signal(bool(0)) + s_axis_tlast = Signal(bool(0)) + s_axis_tid = Signal(intbv(0)[ID_WIDTH:]) + s_axis_tdest = Signal(intbv(0)[DEST_WIDTH:]) + s_axis_tuser = Signal(intbv(0)[USER_WIDTH:]) + m_axis_tready = Signal(bool(0)) + + # Outputs + s_axis_tready = Signal(bool(0)) + m_axis_tdata = Signal(intbv(0)[M_DATA_WIDTH:]) + m_axis_tkeep = Signal(intbv(1)[M_KEEP_WIDTH:]) + m_axis_tvalid = Signal(bool(0)) + m_axis_tlast = Signal(bool(0)) + m_axis_tid = Signal(intbv(0)[ID_WIDTH:]) + m_axis_tdest = Signal(intbv(0)[DEST_WIDTH:]) + m_axis_tuser = Signal(intbv(0)[USER_WIDTH:]) + + # sources and sinks + source_pause = Signal(bool(0)) + sink_pause = Signal(bool(0)) + + source = axis_ep.AXIStreamSource() + + source_logic = source.create_logic( + s_clk, + s_rst, + tdata=s_axis_tdata, + tkeep=s_axis_tkeep, + tvalid=s_axis_tvalid, + tready=s_axis_tready, + tlast=s_axis_tlast, + tid=s_axis_tid, + tdest=s_axis_tdest, + tuser=s_axis_tuser, + pause=source_pause, + name='source' + ) + + sink = axis_ep.AXIStreamSink() + + sink_logic = sink.create_logic( + m_clk, + m_rst, + tdata=m_axis_tdata, + tkeep=m_axis_tkeep, + tvalid=m_axis_tvalid, + tready=m_axis_tready, + tlast=m_axis_tlast, + tid=m_axis_tid, + tdest=m_axis_tdest, + tuser=m_axis_tuser, + pause=sink_pause, + name='sink' + ) + + # DUT + if os.system(build_cmd): + raise Exception("Error running build command") + + dut = Cosimulation( + "vvp -m myhdl %s.vvp -lxt2" % testbench, + s_clk=s_clk, + s_rst=s_rst, + m_clk=m_clk, + m_rst=m_rst, + current_test=current_test, + + s_axis_tdata=s_axis_tdata, + s_axis_tkeep=s_axis_tkeep, + s_axis_tvalid=s_axis_tvalid, + s_axis_tready=s_axis_tready, + s_axis_tlast=s_axis_tlast, + s_axis_tid=s_axis_tid, + s_axis_tdest=s_axis_tdest, + s_axis_tuser=s_axis_tuser, + + m_axis_tdata=m_axis_tdata, + m_axis_tkeep=m_axis_tkeep, + m_axis_tvalid=m_axis_tvalid, + m_axis_tready=m_axis_tready, + m_axis_tlast=m_axis_tlast, + m_axis_tid=m_axis_tid, + m_axis_tdest=m_axis_tdest, + m_axis_tuser=m_axis_tuser + ) + + @always(delay(4)) + def s_clkgen(): + s_clk.next = not s_clk + + @always(delay(5)) + def m_clkgen(): + m_clk.next = not m_clk + + def wait_normal(): + while s_axis_tvalid or m_axis_tvalid: + yield s_clk.posedge + + def wait_pause_source(): + while s_axis_tvalid or m_axis_tvalid: + yield s_clk.posedge + yield s_clk.posedge + source_pause.next = False + yield s_clk.posedge + source_pause.next = True + yield s_clk.posedge + + source_pause.next = False + + def wait_pause_sink(): + while s_axis_tvalid or m_axis_tvalid: + sink_pause.next = True + yield s_clk.posedge + yield s_clk.posedge + yield s_clk.posedge + sink_pause.next = False + yield s_clk.posedge + + @instance + def check(): + yield delay(100) + yield s_clk.posedge + s_rst.next = 1 + m_rst.next = 1 + yield s_clk.posedge + yield s_clk.posedge + yield s_clk.posedge + s_rst.next = 0 + m_rst.next = 0 + yield s_clk.posedge + yield delay(100) + yield s_clk.posedge + + for payload_len in range(1,18): + yield s_clk.posedge + print("test 1: test packet, length %d" % payload_len) + current_test.next = 1 + + test_frame = axis_ep.AXIStreamFrame( + bytearray(range(payload_len)), + id=1, + dest=1, + ) + + for wait in wait_normal, wait_pause_source, wait_pause_sink: + source.send(test_frame) + yield s_clk.posedge + yield s_clk.posedge + + yield wait() + + yield sink.wait() + rx_frame = sink.recv() + + assert rx_frame == test_frame + + assert sink.empty() + + yield delay(100) + + yield s_clk.posedge + print("test 2: back-to-back packets, length %d" % payload_len) + current_test.next = 2 + + test_frame1 = axis_ep.AXIStreamFrame( + bytearray(range(payload_len)), + id=2, + dest=1, + ) + test_frame2 = axis_ep.AXIStreamFrame( + bytearray(range(payload_len)), + id=2, + dest=2, + ) + + for wait in wait_normal, wait_pause_source, wait_pause_sink: + source.send(test_frame1) + source.send(test_frame2) + yield s_clk.posedge + yield s_clk.posedge + + yield wait() + + yield sink.wait() + rx_frame = sink.recv() + + assert rx_frame == test_frame1 + + yield sink.wait() + rx_frame = sink.recv() + + assert rx_frame == test_frame2 + + assert sink.empty() + + yield delay(100) + + yield s_clk.posedge + print("test 3: tuser assert, length %d" % payload_len) + current_test.next = 3 + + test_frame1 = axis_ep.AXIStreamFrame( + bytearray(range(payload_len)), + id=3, + dest=1, + last_cycle_user=1 + ) + test_frame2 = axis_ep.AXIStreamFrame( + bytearray(range(payload_len)), + id=3, + dest=2, + ) + + for wait in wait_normal, wait_pause_source, wait_pause_sink: + source.send(test_frame1) + source.send(test_frame2) + yield s_clk.posedge + yield s_clk.posedge + + yield wait() + + yield sink.wait() + rx_frame = sink.recv() + + assert rx_frame == test_frame1 + assert rx_frame.last_cycle_user + + yield sink.wait() + rx_frame = sink.recv() + + assert rx_frame == test_frame2 + + assert sink.empty() + + 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/lib/axis/tb/test_axis_async_fifo_adapter_8_64.v b/lib/axis/tb/test_axis_async_fifo_adapter_8_64.v new file mode 100644 index 000000000..ddb4a1f35 --- /dev/null +++ b/lib/axis/tb/test_axis_async_fifo_adapter_8_64.v @@ -0,0 +1,165 @@ +/* + +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_async_fifo_adapter + */ +module test_axis_async_fifo_adapter_8_64; + +// Parameters +parameter ADDR_WIDTH = 2; +parameter S_DATA_WIDTH = 8; +parameter S_KEEP_ENABLE = (S_DATA_WIDTH>8); +parameter S_KEEP_WIDTH = (S_DATA_WIDTH/8); +parameter M_DATA_WIDTH = 64; +parameter M_KEEP_ENABLE = (M_DATA_WIDTH>8); +parameter M_KEEP_WIDTH = (M_DATA_WIDTH/8); +parameter ID_ENABLE = 1; +parameter ID_WIDTH = 8; +parameter DEST_ENABLE = 1; +parameter DEST_WIDTH = 8; +parameter USER_ENABLE = 1; +parameter USER_WIDTH = 1; +parameter FRAME_FIFO = 0; +parameter USER_BAD_FRAME_VALUE = 1'b1; +parameter USER_BAD_FRAME_MASK = 1'b1; +parameter DROP_BAD_FRAME = 0; +parameter DROP_WHEN_FULL = 0; + +// Inputs +reg s_clk = 0; +reg s_rst = 0; +reg m_clk = 0; +reg m_rst = 0; +reg [7:0] current_test = 0; + +reg [S_DATA_WIDTH-1:0] s_axis_tdata = 0; +reg [S_KEEP_WIDTH-1:0] s_axis_tkeep = 0; +reg s_axis_tvalid = 0; +reg s_axis_tlast = 0; +reg [ID_WIDTH-1:0] s_axis_tid = 0; +reg [DEST_WIDTH-1:0] s_axis_tdest = 0; +reg [USER_WIDTH-1:0] s_axis_tuser = 0; +reg m_axis_tready = 0; + +// Outputs +wire s_axis_tready; +wire [M_DATA_WIDTH-1:0] m_axis_tdata; +wire [M_KEEP_WIDTH-1:0] m_axis_tkeep; +wire m_axis_tvalid; +wire m_axis_tlast; +wire [ID_WIDTH-1:0] m_axis_tid; +wire [DEST_WIDTH-1:0] m_axis_tdest; +wire [USER_WIDTH-1:0] m_axis_tuser; + +initial begin + // myhdl integration + $from_myhdl( + s_clk, + s_rst, + m_clk, + m_rst, + current_test, + s_axis_tdata, + s_axis_tkeep, + s_axis_tvalid, + s_axis_tlast, + s_axis_tid, + s_axis_tdest, + s_axis_tuser, + m_axis_tready + ); + $to_myhdl( + s_axis_tready, + m_axis_tdata, + m_axis_tkeep, + m_axis_tvalid, + m_axis_tlast, + m_axis_tid, + m_axis_tdest, + m_axis_tuser + ); + + // dump file + $dumpfile("test_axis_async_fifo_adapter_8_64.lxt"); + $dumpvars(0, test_axis_async_fifo_adapter_8_64); +end + +axis_async_fifo_adapter #( + .ADDR_WIDTH(ADDR_WIDTH), + .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_ENABLE(DEST_ENABLE), + .DEST_WIDTH(DEST_WIDTH), + .USER_ENABLE(USER_ENABLE), + .USER_WIDTH(USER_WIDTH), + .FRAME_FIFO(FRAME_FIFO), + .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) +) +UUT ( + // AXI input + .s_clk(s_clk), + .s_rst(s_rst), + .s_axis_tdata(s_axis_tdata), + .s_axis_tkeep(s_axis_tkeep), + .s_axis_tvalid(s_axis_tvalid), + .s_axis_tready(s_axis_tready), + .s_axis_tlast(s_axis_tlast), + .s_axis_tid(s_axis_tid), + .s_axis_tdest(s_axis_tdest), + .s_axis_tuser(s_axis_tuser), + // AXI output + .m_clk(m_clk), + .m_rst(m_rst), + .m_axis_tdata(m_axis_tdata), + .m_axis_tkeep(m_axis_tkeep), + .m_axis_tvalid(m_axis_tvalid), + .m_axis_tready(m_axis_tready), + .m_axis_tlast(m_axis_tlast), + .m_axis_tid(m_axis_tid), + .m_axis_tdest(m_axis_tdest), + .m_axis_tuser(m_axis_tuser), + // Status + .s_status_overflow(), + .s_status_bad_frame(), + .s_status_good_frame(), + .m_status_overflow(), + .m_status_bad_frame(), + .m_status_good_frame() +); + +endmodule diff --git a/lib/axis/tb/test_axis_fifo_adapter_64_8.py b/lib/axis/tb/test_axis_fifo_adapter_64_8.py new file mode 100755 index 000000000..2129221e1 --- /dev/null +++ b/lib/axis/tb/test_axis_fifo_adapter_64_8.py @@ -0,0 +1,312 @@ +#!/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_fifo_adapter' +testbench = 'test_%s_64_8' % module + +srcs = [] + +srcs.append("../rtl/%s.v" % module) +srcs.append("../rtl/axis_adapter.v") +srcs.append("../rtl/axis_fifo.v") +srcs.append("%s.v" % testbench) + +src = ' '.join(srcs) + +build_cmd = "iverilog -o %s.vvp %s" % (testbench, src) + +def bench(): + + # Parameters + ADDR_WIDTH = 2 + S_DATA_WIDTH = 64 + S_KEEP_ENABLE = (S_DATA_WIDTH>8) + S_KEEP_WIDTH = (S_DATA_WIDTH/8) + M_DATA_WIDTH = 8 + M_KEEP_ENABLE = (M_DATA_WIDTH>8) + M_KEEP_WIDTH = (M_DATA_WIDTH/8) + ID_ENABLE = 1 + ID_WIDTH = 8 + DEST_ENABLE = 1 + DEST_WIDTH = 8 + USER_ENABLE = 1 + USER_WIDTH = 1 + FRAME_FIFO = 0 + USER_BAD_FRAME_VALUE = 1 + USER_BAD_FRAME_MASK = 1 + DROP_BAD_FRAME = 0 + DROP_WHEN_FULL = 0 + + # Inputs + clk = Signal(bool(0)) + rst = Signal(bool(0)) + current_test = Signal(intbv(0)[8:]) + + s_axis_tdata = Signal(intbv(0)[S_DATA_WIDTH:]) + s_axis_tkeep = Signal(intbv(1)[S_KEEP_WIDTH:]) + s_axis_tvalid = Signal(bool(0)) + s_axis_tlast = Signal(bool(0)) + s_axis_tid = Signal(intbv(0)[ID_WIDTH:]) + s_axis_tdest = Signal(intbv(0)[DEST_WIDTH:]) + s_axis_tuser = Signal(intbv(0)[USER_WIDTH:]) + m_axis_tready = Signal(bool(0)) + + # Outputs + s_axis_tready = Signal(bool(0)) + m_axis_tdata = Signal(intbv(0)[M_DATA_WIDTH:]) + m_axis_tkeep = Signal(intbv(1)[M_KEEP_WIDTH:]) + m_axis_tvalid = Signal(bool(0)) + m_axis_tlast = Signal(bool(0)) + m_axis_tid = Signal(intbv(0)[ID_WIDTH:]) + m_axis_tdest = Signal(intbv(0)[DEST_WIDTH:]) + m_axis_tuser = Signal(intbv(0)[USER_WIDTH:]) + + # 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=s_axis_tdata, + tkeep=s_axis_tkeep, + tvalid=s_axis_tvalid, + tready=s_axis_tready, + tlast=s_axis_tlast, + tid=s_axis_tid, + tdest=s_axis_tdest, + tuser=s_axis_tuser, + pause=source_pause, + name='source' + ) + + sink = axis_ep.AXIStreamSink() + + sink_logic = sink.create_logic( + clk, + rst, + tdata=m_axis_tdata, + tkeep=m_axis_tkeep, + tvalid=m_axis_tvalid, + tready=m_axis_tready, + tlast=m_axis_tlast, + tid=m_axis_tid, + tdest=m_axis_tdest, + tuser=m_axis_tuser, + pause=sink_pause, + name='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, + + s_axis_tdata=s_axis_tdata, + s_axis_tkeep=s_axis_tkeep, + s_axis_tvalid=s_axis_tvalid, + s_axis_tready=s_axis_tready, + s_axis_tlast=s_axis_tlast, + s_axis_tid=s_axis_tid, + s_axis_tdest=s_axis_tdest, + s_axis_tuser=s_axis_tuser, + + m_axis_tdata=m_axis_tdata, + m_axis_tkeep=m_axis_tkeep, + m_axis_tvalid=m_axis_tvalid, + m_axis_tready=m_axis_tready, + m_axis_tlast=m_axis_tlast, + m_axis_tid=m_axis_tid, + m_axis_tdest=m_axis_tdest, + m_axis_tuser=m_axis_tuser + ) + + @always(delay(4)) + def clkgen(): + clk.next = not clk + + def wait_normal(): + while s_axis_tvalid or m_axis_tvalid: + yield clk.posedge + + def wait_pause_source(): + while s_axis_tvalid or m_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 + + def wait_pause_sink(): + while s_axis_tvalid or m_axis_tvalid: + sink_pause.next = True + yield clk.posedge + yield clk.posedge + yield clk.posedge + sink_pause.next = False + yield clk.posedge + + @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 + + for payload_len in range(1,18): + yield clk.posedge + print("test 1: test packet, length %d" % payload_len) + current_test.next = 1 + + test_frame = axis_ep.AXIStreamFrame( + bytearray(range(payload_len)), + id=1, + dest=1, + ) + + for wait in wait_normal, wait_pause_source, wait_pause_sink: + source.send(test_frame) + yield clk.posedge + yield clk.posedge + + yield wait() + + yield sink.wait() + rx_frame = sink.recv() + + assert rx_frame == test_frame + + assert sink.empty() + + yield delay(100) + + yield clk.posedge + print("test 2: back-to-back packets, length %d" % payload_len) + current_test.next = 2 + + test_frame1 = axis_ep.AXIStreamFrame( + bytearray(range(payload_len)), + id=2, + dest=1, + ) + test_frame2 = axis_ep.AXIStreamFrame( + bytearray(range(payload_len)), + id=2, + dest=2, + ) + + for wait in wait_normal, wait_pause_source, wait_pause_sink: + source.send(test_frame1) + source.send(test_frame2) + yield clk.posedge + yield clk.posedge + + yield wait() + + yield sink.wait() + rx_frame = sink.recv() + + assert rx_frame == test_frame1 + + yield sink.wait() + rx_frame = sink.recv() + + assert rx_frame == test_frame2 + + assert sink.empty() + + yield delay(100) + + yield clk.posedge + print("test 3: tuser assert, length %d" % payload_len) + current_test.next = 3 + + test_frame1 = axis_ep.AXIStreamFrame( + bytearray(range(payload_len)), + id=3, + dest=1, + last_cycle_user=1 + ) + test_frame2 = axis_ep.AXIStreamFrame( + bytearray(range(payload_len)), + id=3, + dest=2, + ) + + for wait in wait_normal, wait_pause_source, wait_pause_sink: + source.send(test_frame1) + source.send(test_frame2) + yield clk.posedge + yield clk.posedge + + yield wait() + + yield sink.wait() + rx_frame = sink.recv() + + assert rx_frame == test_frame1 + assert rx_frame.last_cycle_user + + yield sink.wait() + rx_frame = sink.recv() + + assert rx_frame == test_frame2 + + assert sink.empty() + + 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/lib/axis/tb/test_axis_fifo_adapter_64_8.v b/lib/axis/tb/test_axis_fifo_adapter_64_8.v new file mode 100644 index 000000000..5afd8d8d2 --- /dev/null +++ b/lib/axis/tb/test_axis_fifo_adapter_64_8.v @@ -0,0 +1,156 @@ +/* + +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_fifo_adapter + */ +module test_axis_fifo_adapter_64_8; + +// Parameters +parameter ADDR_WIDTH = 2; +parameter S_DATA_WIDTH = 64; +parameter S_KEEP_ENABLE = (S_DATA_WIDTH>8); +parameter S_KEEP_WIDTH = (S_DATA_WIDTH/8); +parameter M_DATA_WIDTH = 8; +parameter M_KEEP_ENABLE = (M_DATA_WIDTH>8); +parameter M_KEEP_WIDTH = (M_DATA_WIDTH/8); +parameter ID_ENABLE = 1; +parameter ID_WIDTH = 8; +parameter DEST_ENABLE = 1; +parameter DEST_WIDTH = 8; +parameter USER_ENABLE = 1; +parameter USER_WIDTH = 1; +parameter FRAME_FIFO = 0; +parameter USER_BAD_FRAME_VALUE = 1'b1; +parameter USER_BAD_FRAME_MASK = 1'b1; +parameter DROP_BAD_FRAME = 0; +parameter DROP_WHEN_FULL = 0; + +// Inputs +reg clk = 0; +reg rst = 0; +reg [7:0] current_test = 0; + +reg [S_DATA_WIDTH-1:0] s_axis_tdata = 0; +reg [S_KEEP_WIDTH-1:0] s_axis_tkeep = 0; +reg s_axis_tvalid = 0; +reg s_axis_tlast = 0; +reg [ID_WIDTH-1:0] s_axis_tid = 0; +reg [DEST_WIDTH-1:0] s_axis_tdest = 0; +reg [USER_WIDTH-1:0] s_axis_tuser = 0; +reg m_axis_tready = 0; + +// Outputs +wire s_axis_tready; +wire [M_DATA_WIDTH-1:0] m_axis_tdata; +wire [M_KEEP_WIDTH-1:0] m_axis_tkeep; +wire m_axis_tvalid; +wire m_axis_tlast; +wire [ID_WIDTH-1:0] m_axis_tid; +wire [DEST_WIDTH-1:0] m_axis_tdest; +wire [USER_WIDTH-1:0] m_axis_tuser; + +initial begin + // myhdl integration + $from_myhdl( + clk, + rst, + current_test, + s_axis_tdata, + s_axis_tkeep, + s_axis_tvalid, + s_axis_tlast, + s_axis_tid, + s_axis_tdest, + s_axis_tuser, + m_axis_tready + ); + $to_myhdl( + s_axis_tready, + m_axis_tdata, + m_axis_tkeep, + m_axis_tvalid, + m_axis_tlast, + m_axis_tid, + m_axis_tdest, + m_axis_tuser + ); + + // dump file + $dumpfile("test_axis_fifo_adapter_64_8.lxt"); + $dumpvars(0, test_axis_fifo_adapter_64_8); +end + +axis_fifo_adapter #( + .ADDR_WIDTH(ADDR_WIDTH), + .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_ENABLE(DEST_ENABLE), + .DEST_WIDTH(DEST_WIDTH), + .USER_ENABLE(USER_ENABLE), + .USER_WIDTH(USER_WIDTH), + .FRAME_FIFO(FRAME_FIFO), + .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) +) +UUT ( + .clk(clk), + .rst(rst), + // AXI input + .s_axis_tdata(s_axis_tdata), + .s_axis_tkeep(s_axis_tkeep), + .s_axis_tvalid(s_axis_tvalid), + .s_axis_tready(s_axis_tready), + .s_axis_tlast(s_axis_tlast), + .s_axis_tid(s_axis_tid), + .s_axis_tdest(s_axis_tdest), + .s_axis_tuser(s_axis_tuser), + // AXI output + .m_axis_tdata(m_axis_tdata), + .m_axis_tkeep(m_axis_tkeep), + .m_axis_tvalid(m_axis_tvalid), + .m_axis_tready(m_axis_tready), + .m_axis_tlast(m_axis_tlast), + .m_axis_tid(m_axis_tid), + .m_axis_tdest(m_axis_tdest), + .m_axis_tuser(m_axis_tuser), + // Status + .status_overflow(), + .status_bad_frame(), + .status_good_frame() +); + +endmodule diff --git a/lib/axis/tb/test_axis_fifo_adapter_8_64.py b/lib/axis/tb/test_axis_fifo_adapter_8_64.py new file mode 100755 index 000000000..f59dd451a --- /dev/null +++ b/lib/axis/tb/test_axis_fifo_adapter_8_64.py @@ -0,0 +1,312 @@ +#!/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_fifo_adapter' +testbench = 'test_%s_8_64' % module + +srcs = [] + +srcs.append("../rtl/%s.v" % module) +srcs.append("../rtl/axis_adapter.v") +srcs.append("../rtl/axis_fifo.v") +srcs.append("%s.v" % testbench) + +src = ' '.join(srcs) + +build_cmd = "iverilog -o %s.vvp %s" % (testbench, src) + +def bench(): + + # Parameters + ADDR_WIDTH = 2 + S_DATA_WIDTH = 8 + S_KEEP_ENABLE = (S_DATA_WIDTH>8) + S_KEEP_WIDTH = (S_DATA_WIDTH/8) + M_DATA_WIDTH = 64 + M_KEEP_ENABLE = (M_DATA_WIDTH>8) + M_KEEP_WIDTH = (M_DATA_WIDTH/8) + ID_ENABLE = 1 + ID_WIDTH = 8 + DEST_ENABLE = 1 + DEST_WIDTH = 8 + USER_ENABLE = 1 + USER_WIDTH = 1 + FRAME_FIFO = 0 + USER_BAD_FRAME_VALUE = 1 + USER_BAD_FRAME_MASK = 1 + DROP_BAD_FRAME = 0 + DROP_WHEN_FULL = 0 + + # Inputs + clk = Signal(bool(0)) + rst = Signal(bool(0)) + current_test = Signal(intbv(0)[8:]) + + s_axis_tdata = Signal(intbv(0)[S_DATA_WIDTH:]) + s_axis_tkeep = Signal(intbv(1)[S_KEEP_WIDTH:]) + s_axis_tvalid = Signal(bool(0)) + s_axis_tlast = Signal(bool(0)) + s_axis_tid = Signal(intbv(0)[ID_WIDTH:]) + s_axis_tdest = Signal(intbv(0)[DEST_WIDTH:]) + s_axis_tuser = Signal(intbv(0)[USER_WIDTH:]) + m_axis_tready = Signal(bool(0)) + + # Outputs + s_axis_tready = Signal(bool(0)) + m_axis_tdata = Signal(intbv(0)[M_DATA_WIDTH:]) + m_axis_tkeep = Signal(intbv(1)[M_KEEP_WIDTH:]) + m_axis_tvalid = Signal(bool(0)) + m_axis_tlast = Signal(bool(0)) + m_axis_tid = Signal(intbv(0)[ID_WIDTH:]) + m_axis_tdest = Signal(intbv(0)[DEST_WIDTH:]) + m_axis_tuser = Signal(intbv(0)[USER_WIDTH:]) + + # 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=s_axis_tdata, + tkeep=s_axis_tkeep, + tvalid=s_axis_tvalid, + tready=s_axis_tready, + tlast=s_axis_tlast, + tid=s_axis_tid, + tdest=s_axis_tdest, + tuser=s_axis_tuser, + pause=source_pause, + name='source' + ) + + sink = axis_ep.AXIStreamSink() + + sink_logic = sink.create_logic( + clk, + rst, + tdata=m_axis_tdata, + tkeep=m_axis_tkeep, + tvalid=m_axis_tvalid, + tready=m_axis_tready, + tlast=m_axis_tlast, + tid=m_axis_tid, + tdest=m_axis_tdest, + tuser=m_axis_tuser, + pause=sink_pause, + name='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, + + s_axis_tdata=s_axis_tdata, + s_axis_tkeep=s_axis_tkeep, + s_axis_tvalid=s_axis_tvalid, + s_axis_tready=s_axis_tready, + s_axis_tlast=s_axis_tlast, + s_axis_tid=s_axis_tid, + s_axis_tdest=s_axis_tdest, + s_axis_tuser=s_axis_tuser, + + m_axis_tdata=m_axis_tdata, + m_axis_tkeep=m_axis_tkeep, + m_axis_tvalid=m_axis_tvalid, + m_axis_tready=m_axis_tready, + m_axis_tlast=m_axis_tlast, + m_axis_tid=m_axis_tid, + m_axis_tdest=m_axis_tdest, + m_axis_tuser=m_axis_tuser + ) + + @always(delay(4)) + def clkgen(): + clk.next = not clk + + def wait_normal(): + while s_axis_tvalid or m_axis_tvalid: + yield clk.posedge + + def wait_pause_source(): + while s_axis_tvalid or m_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 + + def wait_pause_sink(): + while s_axis_tvalid or m_axis_tvalid: + sink_pause.next = True + yield clk.posedge + yield clk.posedge + yield clk.posedge + sink_pause.next = False + yield clk.posedge + + @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 + + for payload_len in range(1,18): + yield clk.posedge + print("test 1: test packet, length %d" % payload_len) + current_test.next = 1 + + test_frame = axis_ep.AXIStreamFrame( + bytearray(range(payload_len)), + id=1, + dest=1, + ) + + for wait in wait_normal, wait_pause_source, wait_pause_sink: + source.send(test_frame) + yield clk.posedge + yield clk.posedge + + yield wait() + + yield sink.wait() + rx_frame = sink.recv() + + assert rx_frame == test_frame + + assert sink.empty() + + yield delay(100) + + yield clk.posedge + print("test 2: back-to-back packets, length %d" % payload_len) + current_test.next = 2 + + test_frame1 = axis_ep.AXIStreamFrame( + bytearray(range(payload_len)), + id=2, + dest=1, + ) + test_frame2 = axis_ep.AXIStreamFrame( + bytearray(range(payload_len)), + id=2, + dest=2, + ) + + for wait in wait_normal, wait_pause_source, wait_pause_sink: + source.send(test_frame1) + source.send(test_frame2) + yield clk.posedge + yield clk.posedge + + yield wait() + + yield sink.wait() + rx_frame = sink.recv() + + assert rx_frame == test_frame1 + + yield sink.wait() + rx_frame = sink.recv() + + assert rx_frame == test_frame2 + + assert sink.empty() + + yield delay(100) + + yield clk.posedge + print("test 3: tuser assert, length %d" % payload_len) + current_test.next = 3 + + test_frame1 = axis_ep.AXIStreamFrame( + bytearray(range(payload_len)), + id=3, + dest=1, + last_cycle_user=1 + ) + test_frame2 = axis_ep.AXIStreamFrame( + bytearray(range(payload_len)), + id=3, + dest=2, + ) + + for wait in wait_normal, wait_pause_source, wait_pause_sink: + source.send(test_frame1) + source.send(test_frame2) + yield clk.posedge + yield clk.posedge + + yield wait() + + yield sink.wait() + rx_frame = sink.recv() + + assert rx_frame == test_frame1 + assert rx_frame.last_cycle_user + + yield sink.wait() + rx_frame = sink.recv() + + assert rx_frame == test_frame2 + + assert sink.empty() + + 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/lib/axis/tb/test_axis_fifo_adapter_8_64.v b/lib/axis/tb/test_axis_fifo_adapter_8_64.v new file mode 100644 index 000000000..c97a3a422 --- /dev/null +++ b/lib/axis/tb/test_axis_fifo_adapter_8_64.v @@ -0,0 +1,156 @@ +/* + +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_fifo_adapter + */ +module test_axis_fifo_adapter_8_64; + +// Parameters +parameter ADDR_WIDTH = 2; +parameter S_DATA_WIDTH = 8; +parameter S_KEEP_ENABLE = (S_DATA_WIDTH>8); +parameter S_KEEP_WIDTH = (S_DATA_WIDTH/8); +parameter M_DATA_WIDTH = 64; +parameter M_KEEP_ENABLE = (M_DATA_WIDTH>8); +parameter M_KEEP_WIDTH = (M_DATA_WIDTH/8); +parameter ID_ENABLE = 1; +parameter ID_WIDTH = 8; +parameter DEST_ENABLE = 1; +parameter DEST_WIDTH = 8; +parameter USER_ENABLE = 1; +parameter USER_WIDTH = 1; +parameter FRAME_FIFO = 0; +parameter USER_BAD_FRAME_VALUE = 1'b1; +parameter USER_BAD_FRAME_MASK = 1'b1; +parameter DROP_BAD_FRAME = 0; +parameter DROP_WHEN_FULL = 0; + +// Inputs +reg clk = 0; +reg rst = 0; +reg [7:0] current_test = 0; + +reg [S_DATA_WIDTH-1:0] s_axis_tdata = 0; +reg [S_KEEP_WIDTH-1:0] s_axis_tkeep = 0; +reg s_axis_tvalid = 0; +reg s_axis_tlast = 0; +reg [ID_WIDTH-1:0] s_axis_tid = 0; +reg [DEST_WIDTH-1:0] s_axis_tdest = 0; +reg [USER_WIDTH-1:0] s_axis_tuser = 0; +reg m_axis_tready = 0; + +// Outputs +wire s_axis_tready; +wire [M_DATA_WIDTH-1:0] m_axis_tdata; +wire [M_KEEP_WIDTH-1:0] m_axis_tkeep; +wire m_axis_tvalid; +wire m_axis_tlast; +wire [ID_WIDTH-1:0] m_axis_tid; +wire [DEST_WIDTH-1:0] m_axis_tdest; +wire [USER_WIDTH-1:0] m_axis_tuser; + +initial begin + // myhdl integration + $from_myhdl( + clk, + rst, + current_test, + s_axis_tdata, + s_axis_tkeep, + s_axis_tvalid, + s_axis_tlast, + s_axis_tid, + s_axis_tdest, + s_axis_tuser, + m_axis_tready + ); + $to_myhdl( + s_axis_tready, + m_axis_tdata, + m_axis_tkeep, + m_axis_tvalid, + m_axis_tlast, + m_axis_tid, + m_axis_tdest, + m_axis_tuser + ); + + // dump file + $dumpfile("test_axis_fifo_adapter_8_64.lxt"); + $dumpvars(0, test_axis_fifo_adapter_8_64); +end + +axis_fifo_adapter #( + .ADDR_WIDTH(ADDR_WIDTH), + .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_ENABLE(DEST_ENABLE), + .DEST_WIDTH(DEST_WIDTH), + .USER_ENABLE(USER_ENABLE), + .USER_WIDTH(USER_WIDTH), + .FRAME_FIFO(FRAME_FIFO), + .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) +) +UUT ( + .clk(clk), + .rst(rst), + // AXI input + .s_axis_tdata(s_axis_tdata), + .s_axis_tkeep(s_axis_tkeep), + .s_axis_tvalid(s_axis_tvalid), + .s_axis_tready(s_axis_tready), + .s_axis_tlast(s_axis_tlast), + .s_axis_tid(s_axis_tid), + .s_axis_tdest(s_axis_tdest), + .s_axis_tuser(s_axis_tuser), + // AXI output + .m_axis_tdata(m_axis_tdata), + .m_axis_tkeep(m_axis_tkeep), + .m_axis_tvalid(m_axis_tvalid), + .m_axis_tready(m_axis_tready), + .m_axis_tlast(m_axis_tlast), + .m_axis_tid(m_axis_tid), + .m_axis_tdest(m_axis_tdest), + .m_axis_tuser(m_axis_tuser), + // Status + .status_overflow(), + .status_bad_frame(), + .status_good_frame() +); + +endmodule