From 9d813226d0e17c2737f542ec0ca181e0c03b5907 Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Wed, 24 Oct 2018 22:16:05 -0700 Subject: [PATCH] Convert generated demux to verilog parametrized demux --- rtl/axis_demux.py | 324 --------------------------------- rtl/axis_demux.v | 258 ++++++++++++++++++++++++++ rtl/axis_demux_4.v | 335 ---------------------------------- tb/test_axis_demux_4.py | 359 +++++++++++++++++-------------------- tb/test_axis_demux_4.v | 179 ++++++------------ tb/test_axis_demux_4_64.py | 359 +++++++++++++++++-------------------- tb/test_axis_demux_4_64.v | 179 ++++++------------ 7 files changed, 706 insertions(+), 1287 deletions(-) delete mode 100755 rtl/axis_demux.py create mode 100644 rtl/axis_demux.v delete mode 100644 rtl/axis_demux_4.v diff --git a/rtl/axis_demux.py b/rtl/axis_demux.py deleted file mode 100755 index 4d2832484..000000000 --- a/rtl/axis_demux.py +++ /dev/null @@ -1,324 +0,0 @@ -#!/usr/bin/env python -""" -Generates an AXI Stream demux with the specified number of ports -""" - -from __future__ import print_function - -import argparse -import math -from jinja2 import Template - -def main(): - parser = argparse.ArgumentParser(description=__doc__.strip()) - parser.add_argument('-p', '--ports', type=int, default=4, help="number of ports") - parser.add_argument('-n', '--name', type=str, help="module name") - parser.add_argument('-o', '--output', type=str, help="output file name") - - args = parser.parse_args() - - try: - generate(**args.__dict__) - except IOError as ex: - print(ex) - exit(1) - -def generate(ports=4, name=None, output=None): - if name is None: - name = "axis_demux_{0}".format(ports) - - if output is None: - output = name + ".v" - - print("Opening file '{0}'...".format(output)) - - output_file = open(output, 'w') - - print("Generating {0} port AXI Stream demux {1}...".format(ports, name)) - - select_width = int(math.ceil(math.log(ports, 2))) - - t = Template(u"""/* - -Copyright (c) 2014-2018 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 {{n}} port demultiplexer - */ -module {{name}} # -( - parameter DATA_WIDTH = 8, - parameter KEEP_ENABLE = (DATA_WIDTH>8), - parameter KEEP_WIDTH = (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 -) -( - input wire clk, - input wire rst, - - /* - * AXI input - */ - input wire [DATA_WIDTH-1:0] input_axis_tdata, - input wire [KEEP_WIDTH-1:0] input_axis_tkeep, - input wire input_axis_tvalid, - output wire input_axis_tready, - input wire input_axis_tlast, - input wire [ID_WIDTH-1:0] input_axis_tid, - input wire [DEST_WIDTH-1:0] input_axis_tdest, - input wire [USER_WIDTH-1:0] input_axis_tuser, - - /* - * AXI outputs - */ -{%- for p in ports %} - output wire [DATA_WIDTH-1:0] output_{{p}}_axis_tdata, - output wire [KEEP_WIDTH-1:0] output_{{p}}_axis_tkeep, - output wire output_{{p}}_axis_tvalid, - input wire output_{{p}}_axis_tready, - output wire output_{{p}}_axis_tlast, - output wire [ID_WIDTH-1:0] output_{{p}}_axis_tid, - output wire [DEST_WIDTH-1:0] output_{{p}}_axis_tdest, - output wire [USER_WIDTH-1:0] output_{{p}}_axis_tuser, -{% endfor %} - /* - * Control - */ - input wire enable, - input wire [{{w-1}}:0] select -); - -reg [{{w-1}}:0] select_reg = {{w}}'d0, select_next; -reg frame_reg = 1'b0, frame_next; - -reg input_axis_tready_reg = 1'b0, input_axis_tready_next; - -// internal datapath -reg [DATA_WIDTH-1:0] output_axis_tdata_int; -reg [KEEP_WIDTH-1:0] output_axis_tkeep_int; -reg output_axis_tvalid_int; -reg output_axis_tready_int_reg = 1'b0; -reg output_axis_tlast_int; -reg [ID_WIDTH-1:0] output_axis_tid_int; -reg [DEST_WIDTH-1:0] output_axis_tdest_int; -reg [USER_WIDTH-1:0] output_axis_tuser_int; -wire output_axis_tready_int_early; - -assign input_axis_tready = input_axis_tready_reg; - -// mux for output control signals -reg current_output_tready; -reg current_output_tvalid; -always @* begin - case (select_reg) -{%- for p in ports %} - {{w}}'d{{p}}: begin - current_output_tvalid = output_{{p}}_axis_tvalid; - current_output_tready = output_{{p}}_axis_tready; - end -{%- endfor %} - default: begin - current_output_tvalid = 1'b0; - current_output_tready = 1'b0; - end - endcase -end - -always @* begin - select_next = select_reg; - frame_next = frame_reg; - - input_axis_tready_next = 1'b0; - - if (input_axis_tvalid & input_axis_tready) begin - // end of frame detection - if (input_axis_tlast) begin - frame_next = 1'b0; - end - end - - if (~frame_reg & enable & input_axis_tvalid & ~current_output_tvalid) begin - // start of frame, grab select value - frame_next = 1'b1; - select_next = select; - end - - input_axis_tready_next = output_axis_tready_int_early & frame_next; - - output_axis_tdata_int = input_axis_tdata; - output_axis_tkeep_int = input_axis_tkeep; - output_axis_tvalid_int = input_axis_tvalid & input_axis_tready; - output_axis_tlast_int = input_axis_tlast; - output_axis_tid_int = input_axis_tid; - output_axis_tdest_int = input_axis_tdest; - output_axis_tuser_int = input_axis_tuser; -end - -always @(posedge clk) begin - if (rst) begin - select_reg <= {{w}}'d0; - frame_reg <= 1'b0; - input_axis_tready_reg <= 1'b0; - end else begin - select_reg <= select_next; - frame_reg <= frame_next; - input_axis_tready_reg <= input_axis_tready_next; - end -end - -// output datapath logic -reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}}; -reg [KEEP_WIDTH-1:0] output_axis_tkeep_reg = {KEEP_WIDTH{1'b0}}; -{%- for p in ports %} -reg output_{{p}}_axis_tvalid_reg = 1'b0, output_{{p}}_axis_tvalid_next; -{%- endfor %} -reg output_axis_tlast_reg = 1'b0; -reg [ID_WIDTH-1:0] output_axis_tid_reg = {ID_WIDTH{1'b0}}; -reg [DEST_WIDTH-1:0] output_axis_tdest_reg = {DEST_WIDTH{1'b0}}; -reg [USER_WIDTH-1:0] output_axis_tuser_reg = {USER_WIDTH{1'b0}}; - -reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = {DATA_WIDTH{1'b0}}; -reg [KEEP_WIDTH-1:0] temp_axis_tkeep_reg = {KEEP_WIDTH{1'b0}}; -reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next; -reg temp_axis_tlast_reg = 1'b0; -reg [ID_WIDTH-1:0] temp_axis_tid_reg = {ID_WIDTH{1'b0}}; -reg [DEST_WIDTH-1:0] temp_axis_tdest_reg = {DEST_WIDTH{1'b0}}; -reg [USER_WIDTH-1:0] temp_axis_tuser_reg = {USER_WIDTH{1'b0}}; - -// datapath control -reg store_axis_int_to_output; -reg store_axis_int_to_temp; -reg store_axis_temp_to_output; -{% for p in ports %} -assign output_{{p}}_axis_tdata = output_axis_tdata_reg; -assign output_{{p}}_axis_tkeep = KEEP_ENABLE ? output_axis_tkeep_reg : {KEEP_WIDTH{1'b1}}; -assign output_{{p}}_axis_tvalid = output_{{p}}_axis_tvalid_reg; -assign output_{{p}}_axis_tlast = output_axis_tlast_reg; -assign output_{{p}}_axis_tid = ID_ENABLE ? output_axis_tid_reg : {ID_WIDTH{1'b0}}; -assign output_{{p}}_axis_tdest = DEST_ENABLE ? output_axis_tdest_reg : {DEST_WIDTH{1'b0}}; -assign output_{{p}}_axis_tuser = USER_ENABLE ? output_axis_tuser_int : {USER_WIDTH{1'b0}}; -{% endfor %} -// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input) -assign output_axis_tready_int_early = current_output_tready | (~temp_axis_tvalid_reg & (~current_output_tvalid | ~output_axis_tvalid_int)); - -always @* begin - // transfer sink ready state to source -{%- for p in ports %} - output_{{p}}_axis_tvalid_next = output_{{p}}_axis_tvalid_reg; -{%- endfor %} - temp_axis_tvalid_next = temp_axis_tvalid_reg; - - store_axis_int_to_output = 1'b0; - store_axis_int_to_temp = 1'b0; - store_axis_temp_to_output = 1'b0; - - if (output_axis_tready_int_reg) begin - // input is ready - if (current_output_tready | ~current_output_tvalid) begin - // output is ready or currently not valid, transfer data to output -{%- for p in ports %} - output_{{p}}_axis_tvalid_next = output_axis_tvalid_int & (select_reg == {{w}}'d{{p}}); -{%- endfor %} - store_axis_int_to_output = 1'b1; - end else begin - // output is not ready, store input in temp - temp_axis_tvalid_next = output_axis_tvalid_int; - store_axis_int_to_temp = 1'b1; - end - end else if (current_output_tready) begin - // input is not ready, but output is ready -{%- for p in ports %} - output_{{p}}_axis_tvalid_next = temp_axis_tvalid_reg & (select_reg == {{w}}'d{{p}}); -{%- endfor %} - temp_axis_tvalid_next = 1'b0; - store_axis_temp_to_output = 1'b1; - end -end - -always @(posedge clk) begin - if (rst) begin -{%- for p in ports %} - output_{{p}}_axis_tvalid_reg <= 1'b0; -{%- endfor %} - output_axis_tready_int_reg <= 1'b0; - temp_axis_tvalid_reg <= 1'b0; - end else begin -{%- for p in ports %} - output_{{p}}_axis_tvalid_reg <= output_{{p}}_axis_tvalid_next; -{%- endfor %} - output_axis_tready_int_reg <= output_axis_tready_int_early; - temp_axis_tvalid_reg <= temp_axis_tvalid_next; - end - - // datapath - if (store_axis_int_to_output) begin - output_axis_tdata_reg <= output_axis_tdata_int; - output_axis_tkeep_reg <= output_axis_tkeep_int; - output_axis_tlast_reg <= output_axis_tlast_int; - output_axis_tid_reg <= output_axis_tid_int; - output_axis_tdest_reg <= output_axis_tdest_int; - output_axis_tuser_reg <= output_axis_tuser_int; - end else if (store_axis_temp_to_output) begin - output_axis_tdata_reg <= temp_axis_tdata_reg; - output_axis_tkeep_reg <= temp_axis_tkeep_reg; - output_axis_tlast_reg <= temp_axis_tlast_reg; - output_axis_tid_reg <= temp_axis_tid_reg; - output_axis_tdest_reg <= temp_axis_tdest_reg; - output_axis_tuser_reg <= temp_axis_tuser_reg; - end - - if (store_axis_int_to_temp) begin - temp_axis_tdata_reg <= output_axis_tdata_int; - temp_axis_tkeep_reg <= output_axis_tkeep_int; - temp_axis_tlast_reg <= output_axis_tlast_int; - temp_axis_tid_reg <= output_axis_tid_int; - temp_axis_tdest_reg <= output_axis_tdest_int; - temp_axis_tuser_reg <= output_axis_tuser_int; - end -end - -endmodule - -""") - - output_file.write(t.render( - n=ports, - w=select_width, - name=name, - ports=range(ports) - )) - - print("Done") - -if __name__ == "__main__": - main() - diff --git a/rtl/axis_demux.v b/rtl/axis_demux.v new file mode 100644 index 000000000..6edff1eec --- /dev/null +++ b/rtl/axis_demux.v @@ -0,0 +1,258 @@ +/* + +Copyright (c) 2018 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 demultiplexer + */ +module axis_demux # +( + parameter M_COUNT = 4, + parameter DATA_WIDTH = 8, + parameter KEEP_ENABLE = (DATA_WIDTH>8), + parameter KEEP_WIDTH = (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 +) +( + input wire clk, + input wire rst, + + /* + * AXI input + */ + input wire [DATA_WIDTH-1:0] s_axis_tdata, + input wire [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 outputs + */ + output wire [M_COUNT*DATA_WIDTH-1:0] m_axis_tdata, + output wire [M_COUNT*KEEP_WIDTH-1:0] m_axis_tkeep, + output wire [M_COUNT-1:0] m_axis_tvalid, + input wire [M_COUNT-1:0] m_axis_tready, + output wire [M_COUNT-1:0] m_axis_tlast, + output wire [M_COUNT*ID_WIDTH-1:0] m_axis_tid, + output wire [M_COUNT*DEST_WIDTH-1:0] m_axis_tdest, + output wire [M_COUNT*USER_WIDTH-1:0] m_axis_tuser, + + /* + * Control + */ + input wire enable, + input wire drop, + input wire [$clog2(M_COUNT)-1:0] select +); + +parameter CL_M_COUNT = $clog2(M_COUNT); + +reg [CL_M_COUNT-1:0] select_reg = {CL_M_COUNT{1'b0}}, select_ctl, select_next; +reg drop_reg = 1'b0, drop_ctl, drop_next; +reg frame_reg = 1'b0, frame_ctl, frame_next; + +reg s_axis_tready_reg = 1'b0, s_axis_tready_next; + +// internal datapath +reg [DATA_WIDTH-1:0] m_axis_tdata_int; +reg [KEEP_WIDTH-1:0] m_axis_tkeep_int; +reg [M_COUNT-1:0] m_axis_tvalid_int; +reg m_axis_tready_int_reg = 1'b0; +reg m_axis_tlast_int; +reg [ID_WIDTH-1:0] m_axis_tid_int; +reg [DEST_WIDTH-1:0] m_axis_tdest_int; +reg [USER_WIDTH-1:0] m_axis_tuser_int; +wire m_axis_tready_int_early; + +assign s_axis_tready = s_axis_tready_reg && enable; + +integer i; + +always @* begin + select_next = select_reg; + select_ctl = select_reg; + drop_next = drop_reg; + drop_ctl = drop_reg; + frame_next = frame_reg; + frame_ctl = frame_reg; + + s_axis_tready_next = 1'b0; + + if (s_axis_tvalid && s_axis_tready) begin + // end of frame detection + if (s_axis_tlast) begin + frame_next = 1'b0; + drop_next = 1'b0; + end + end + + if (!frame_reg && s_axis_tvalid && s_axis_tready) begin + // start of frame, grab select value + select_ctl = select; + drop_ctl = drop; + frame_ctl = 1'b1; + if (!(s_axis_tready && s_axis_tvalid && s_axis_tlast)) begin + select_next = select_ctl; + drop_next = drop_ctl; + frame_next = 1'b1; + end + end + + s_axis_tready_next = (m_axis_tready_int_early || drop_ctl); + + m_axis_tdata_int = s_axis_tdata; + m_axis_tkeep_int = s_axis_tkeep; + m_axis_tvalid_int = (s_axis_tvalid && s_axis_tready && !drop_ctl) << select_ctl; + m_axis_tlast_int = s_axis_tlast; + m_axis_tid_int = s_axis_tid; + m_axis_tdest_int = s_axis_tdest; + m_axis_tuser_int = s_axis_tuser; +end + +always @(posedge clk) begin + if (rst) begin + select_reg <= 2'd0; + drop_reg <= 1'b0; + frame_reg <= 1'b0; + s_axis_tready_reg <= 1'b0; + end else begin + select_reg <= select_next; + drop_reg <= drop_next; + frame_reg <= frame_next; + s_axis_tready_reg <= s_axis_tready_next; + end +end + +// output datapath logic +reg [DATA_WIDTH-1:0] m_axis_tdata_reg = {DATA_WIDTH{1'b0}}; +reg [KEEP_WIDTH-1:0] m_axis_tkeep_reg = {KEEP_WIDTH{1'b0}}; +reg [M_COUNT-1:0] m_axis_tvalid_reg = {M_COUNT{1'b0}}, m_axis_tvalid_next; +reg m_axis_tlast_reg = 1'b0; +reg [ID_WIDTH-1:0] m_axis_tid_reg = {ID_WIDTH{1'b0}}; +reg [DEST_WIDTH-1:0] m_axis_tdest_reg = {DEST_WIDTH{1'b0}}; +reg [USER_WIDTH-1:0] m_axis_tuser_reg = {USER_WIDTH{1'b0}}; + +reg [DATA_WIDTH-1:0] temp_m_axis_tdata_reg = {DATA_WIDTH{1'b0}}; +reg [KEEP_WIDTH-1:0] temp_m_axis_tkeep_reg = {KEEP_WIDTH{1'b0}}; +reg [M_COUNT-1:0] temp_m_axis_tvalid_reg = {M_COUNT{1'b0}}, temp_m_axis_tvalid_next; +reg temp_m_axis_tlast_reg = 1'b0; +reg [ID_WIDTH-1:0] temp_m_axis_tid_reg = {ID_WIDTH{1'b0}}; +reg [DEST_WIDTH-1:0] temp_m_axis_tdest_reg = {DEST_WIDTH{1'b0}}; +reg [USER_WIDTH-1:0] temp_m_axis_tuser_reg = {USER_WIDTH{1'b0}}; + +// datapath control +reg store_axis_int_to_output; +reg store_axis_int_to_temp; +reg store_axis_temp_to_output; + +assign m_axis_tdata = {M_COUNT{m_axis_tdata_reg}}; +assign m_axis_tkeep = KEEP_ENABLE ? {M_COUNT{m_axis_tkeep_reg}} : {M_COUNT*KEEP_WIDTH{1'b1}}; +assign m_axis_tvalid = m_axis_tvalid_reg; +assign m_axis_tlast = {M_COUNT{m_axis_tlast_reg}}; +assign m_axis_tid = ID_ENABLE ? {M_COUNT{m_axis_tid_reg}} : {M_COUNT*ID_WIDTH{1'b0}}; +assign m_axis_tdest = DEST_ENABLE ? {M_COUNT{m_axis_tdest_reg}} : {M_COUNT*DEST_WIDTH{1'b0}}; +assign m_axis_tuser = USER_ENABLE ? {M_COUNT{m_axis_tuser_reg}} : {M_COUNT*USER_WIDTH{1'b0}}; + +// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input) +assign m_axis_tready_int_early = (m_axis_tready & m_axis_tvalid) || (!temp_m_axis_tvalid_reg && (!m_axis_tvalid || !m_axis_tvalid_int)); + +always @* begin + // transfer sink ready state to source + m_axis_tvalid_next = m_axis_tvalid_reg; + temp_m_axis_tvalid_next = temp_m_axis_tvalid_reg; + + store_axis_int_to_output = 1'b0; + store_axis_int_to_temp = 1'b0; + store_axis_temp_to_output = 1'b0; + + if (m_axis_tready_int_reg) begin + // input is ready + if ((m_axis_tready & m_axis_tvalid) || !m_axis_tvalid) begin + // output is ready or currently not valid, transfer data to output + m_axis_tvalid_next = m_axis_tvalid_int; + store_axis_int_to_output = 1'b1; + end else begin + // output is not ready, store input in temp + temp_m_axis_tvalid_next = m_axis_tvalid_int; + store_axis_int_to_temp = 1'b1; + end + end else if (m_axis_tready & m_axis_tvalid) begin + // input is not ready, but output is ready + m_axis_tvalid_next = temp_m_axis_tvalid_reg; + temp_m_axis_tvalid_next = 1'b0; + store_axis_temp_to_output = 1'b1; + end +end + +always @(posedge clk) begin + if (rst) begin + m_axis_tvalid_reg <= {M_COUNT{1'b0}}; + m_axis_tready_int_reg <= 1'b0; + temp_m_axis_tvalid_reg <= 1'b0; + end else begin + m_axis_tvalid_reg <= m_axis_tvalid_next; + m_axis_tready_int_reg <= m_axis_tready_int_early; + temp_m_axis_tvalid_reg <= temp_m_axis_tvalid_next; + end + + // datapath + if (store_axis_int_to_output) begin + m_axis_tdata_reg <= m_axis_tdata_int; + m_axis_tkeep_reg <= m_axis_tkeep_int; + m_axis_tlast_reg <= m_axis_tlast_int; + m_axis_tid_reg <= m_axis_tid_int; + m_axis_tdest_reg <= m_axis_tdest_int; + m_axis_tuser_reg <= m_axis_tuser_int; + end else if (store_axis_temp_to_output) begin + m_axis_tdata_reg <= temp_m_axis_tdata_reg; + m_axis_tkeep_reg <= temp_m_axis_tkeep_reg; + m_axis_tlast_reg <= temp_m_axis_tlast_reg; + m_axis_tid_reg <= temp_m_axis_tid_reg; + m_axis_tdest_reg <= temp_m_axis_tdest_reg; + m_axis_tuser_reg <= temp_m_axis_tuser_reg; + end + + if (store_axis_int_to_temp) begin + temp_m_axis_tdata_reg <= m_axis_tdata_int; + temp_m_axis_tkeep_reg <= m_axis_tkeep_int; + temp_m_axis_tlast_reg <= m_axis_tlast_int; + temp_m_axis_tid_reg <= m_axis_tid_int; + temp_m_axis_tdest_reg <= m_axis_tdest_int; + temp_m_axis_tuser_reg <= m_axis_tuser_int; + end +end + +endmodule diff --git a/rtl/axis_demux_4.v b/rtl/axis_demux_4.v deleted file mode 100644 index 2e12aebb9..000000000 --- a/rtl/axis_demux_4.v +++ /dev/null @@ -1,335 +0,0 @@ -/* - -Copyright (c) 2014-2018 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 4 port demultiplexer - */ -module axis_demux_4 # -( - parameter DATA_WIDTH = 8, - parameter KEEP_ENABLE = (DATA_WIDTH>8), - parameter KEEP_WIDTH = (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 -) -( - input wire clk, - input wire rst, - - /* - * AXI input - */ - input wire [DATA_WIDTH-1:0] input_axis_tdata, - input wire [KEEP_WIDTH-1:0] input_axis_tkeep, - input wire input_axis_tvalid, - output wire input_axis_tready, - input wire input_axis_tlast, - input wire [ID_WIDTH-1:0] input_axis_tid, - input wire [DEST_WIDTH-1:0] input_axis_tdest, - input wire [USER_WIDTH-1:0] input_axis_tuser, - - /* - * AXI outputs - */ - output wire [DATA_WIDTH-1:0] output_0_axis_tdata, - output wire [KEEP_WIDTH-1:0] output_0_axis_tkeep, - output wire output_0_axis_tvalid, - input wire output_0_axis_tready, - output wire output_0_axis_tlast, - output wire [ID_WIDTH-1:0] output_0_axis_tid, - output wire [DEST_WIDTH-1:0] output_0_axis_tdest, - output wire [USER_WIDTH-1:0] output_0_axis_tuser, - - output wire [DATA_WIDTH-1:0] output_1_axis_tdata, - output wire [KEEP_WIDTH-1:0] output_1_axis_tkeep, - output wire output_1_axis_tvalid, - input wire output_1_axis_tready, - output wire output_1_axis_tlast, - output wire [ID_WIDTH-1:0] output_1_axis_tid, - output wire [DEST_WIDTH-1:0] output_1_axis_tdest, - output wire [USER_WIDTH-1:0] output_1_axis_tuser, - - output wire [DATA_WIDTH-1:0] output_2_axis_tdata, - output wire [KEEP_WIDTH-1:0] output_2_axis_tkeep, - output wire output_2_axis_tvalid, - input wire output_2_axis_tready, - output wire output_2_axis_tlast, - output wire [ID_WIDTH-1:0] output_2_axis_tid, - output wire [DEST_WIDTH-1:0] output_2_axis_tdest, - output wire [USER_WIDTH-1:0] output_2_axis_tuser, - - output wire [DATA_WIDTH-1:0] output_3_axis_tdata, - output wire [KEEP_WIDTH-1:0] output_3_axis_tkeep, - output wire output_3_axis_tvalid, - input wire output_3_axis_tready, - output wire output_3_axis_tlast, - output wire [ID_WIDTH-1:0] output_3_axis_tid, - output wire [DEST_WIDTH-1:0] output_3_axis_tdest, - output wire [USER_WIDTH-1:0] output_3_axis_tuser, - - /* - * Control - */ - input wire enable, - input wire [1:0] select -); - -reg [1:0] select_reg = 2'd0, select_next; -reg frame_reg = 1'b0, frame_next; - -reg input_axis_tready_reg = 1'b0, input_axis_tready_next; - -// internal datapath -reg [DATA_WIDTH-1:0] output_axis_tdata_int; -reg [KEEP_WIDTH-1:0] output_axis_tkeep_int; -reg output_axis_tvalid_int; -reg output_axis_tready_int_reg = 1'b0; -reg output_axis_tlast_int; -reg [ID_WIDTH-1:0] output_axis_tid_int; -reg [DEST_WIDTH-1:0] output_axis_tdest_int; -reg [USER_WIDTH-1:0] output_axis_tuser_int; -wire output_axis_tready_int_early; - -assign input_axis_tready = input_axis_tready_reg; - -// mux for output control signals -reg current_output_tready; -reg current_output_tvalid; -always @* begin - case (select_reg) - 2'd0: begin - current_output_tvalid = output_0_axis_tvalid; - current_output_tready = output_0_axis_tready; - end - 2'd1: begin - current_output_tvalid = output_1_axis_tvalid; - current_output_tready = output_1_axis_tready; - end - 2'd2: begin - current_output_tvalid = output_2_axis_tvalid; - current_output_tready = output_2_axis_tready; - end - 2'd3: begin - current_output_tvalid = output_3_axis_tvalid; - current_output_tready = output_3_axis_tready; - end - default: begin - current_output_tvalid = 1'b0; - current_output_tready = 1'b0; - end - endcase -end - -always @* begin - select_next = select_reg; - frame_next = frame_reg; - - input_axis_tready_next = 1'b0; - - if (input_axis_tvalid & input_axis_tready) begin - // end of frame detection - if (input_axis_tlast) begin - frame_next = 1'b0; - end - end - - if (~frame_reg & enable & input_axis_tvalid & ~current_output_tvalid) begin - // start of frame, grab select value - frame_next = 1'b1; - select_next = select; - end - - input_axis_tready_next = output_axis_tready_int_early & frame_next; - - output_axis_tdata_int = input_axis_tdata; - output_axis_tkeep_int = input_axis_tkeep; - output_axis_tvalid_int = input_axis_tvalid & input_axis_tready; - output_axis_tlast_int = input_axis_tlast; - output_axis_tid_int = input_axis_tid; - output_axis_tdest_int = input_axis_tdest; - output_axis_tuser_int = input_axis_tuser; -end - -always @(posedge clk) begin - if (rst) begin - select_reg <= 2'd0; - frame_reg <= 1'b0; - input_axis_tready_reg <= 1'b0; - end else begin - select_reg <= select_next; - frame_reg <= frame_next; - input_axis_tready_reg <= input_axis_tready_next; - end -end - -// output datapath logic -reg [DATA_WIDTH-1:0] output_axis_tdata_reg = {DATA_WIDTH{1'b0}}; -reg [KEEP_WIDTH-1:0] output_axis_tkeep_reg = {KEEP_WIDTH{1'b0}}; -reg output_0_axis_tvalid_reg = 1'b0, output_0_axis_tvalid_next; -reg output_1_axis_tvalid_reg = 1'b0, output_1_axis_tvalid_next; -reg output_2_axis_tvalid_reg = 1'b0, output_2_axis_tvalid_next; -reg output_3_axis_tvalid_reg = 1'b0, output_3_axis_tvalid_next; -reg output_axis_tlast_reg = 1'b0; -reg [ID_WIDTH-1:0] output_axis_tid_reg = {ID_WIDTH{1'b0}}; -reg [DEST_WIDTH-1:0] output_axis_tdest_reg = {DEST_WIDTH{1'b0}}; -reg [USER_WIDTH-1:0] output_axis_tuser_reg = {USER_WIDTH{1'b0}}; - -reg [DATA_WIDTH-1:0] temp_axis_tdata_reg = {DATA_WIDTH{1'b0}}; -reg [KEEP_WIDTH-1:0] temp_axis_tkeep_reg = {KEEP_WIDTH{1'b0}}; -reg temp_axis_tvalid_reg = 1'b0, temp_axis_tvalid_next; -reg temp_axis_tlast_reg = 1'b0; -reg [ID_WIDTH-1:0] temp_axis_tid_reg = {ID_WIDTH{1'b0}}; -reg [DEST_WIDTH-1:0] temp_axis_tdest_reg = {DEST_WIDTH{1'b0}}; -reg [USER_WIDTH-1:0] temp_axis_tuser_reg = {USER_WIDTH{1'b0}}; - -// datapath control -reg store_axis_int_to_output; -reg store_axis_int_to_temp; -reg store_axis_temp_to_output; - -assign output_0_axis_tdata = output_axis_tdata_reg; -assign output_0_axis_tkeep = KEEP_ENABLE ? output_axis_tkeep_reg : {KEEP_WIDTH{1'b1}}; -assign output_0_axis_tvalid = output_0_axis_tvalid_reg; -assign output_0_axis_tlast = output_axis_tlast_reg; -assign output_0_axis_tid = ID_ENABLE ? output_axis_tid_reg : {ID_WIDTH{1'b0}}; -assign output_0_axis_tdest = DEST_ENABLE ? output_axis_tdest_reg : {DEST_WIDTH{1'b0}}; -assign output_0_axis_tuser = USER_ENABLE ? output_axis_tuser_int : {USER_WIDTH{1'b0}}; - -assign output_1_axis_tdata = output_axis_tdata_reg; -assign output_1_axis_tkeep = KEEP_ENABLE ? output_axis_tkeep_reg : {KEEP_WIDTH{1'b1}}; -assign output_1_axis_tvalid = output_1_axis_tvalid_reg; -assign output_1_axis_tlast = output_axis_tlast_reg; -assign output_1_axis_tid = ID_ENABLE ? output_axis_tid_reg : {ID_WIDTH{1'b0}}; -assign output_1_axis_tdest = DEST_ENABLE ? output_axis_tdest_reg : {DEST_WIDTH{1'b0}}; -assign output_1_axis_tuser = USER_ENABLE ? output_axis_tuser_int : {USER_WIDTH{1'b0}}; - -assign output_2_axis_tdata = output_axis_tdata_reg; -assign output_2_axis_tkeep = KEEP_ENABLE ? output_axis_tkeep_reg : {KEEP_WIDTH{1'b1}}; -assign output_2_axis_tvalid = output_2_axis_tvalid_reg; -assign output_2_axis_tlast = output_axis_tlast_reg; -assign output_2_axis_tid = ID_ENABLE ? output_axis_tid_reg : {ID_WIDTH{1'b0}}; -assign output_2_axis_tdest = DEST_ENABLE ? output_axis_tdest_reg : {DEST_WIDTH{1'b0}}; -assign output_2_axis_tuser = USER_ENABLE ? output_axis_tuser_int : {USER_WIDTH{1'b0}}; - -assign output_3_axis_tdata = output_axis_tdata_reg; -assign output_3_axis_tkeep = KEEP_ENABLE ? output_axis_tkeep_reg : {KEEP_WIDTH{1'b1}}; -assign output_3_axis_tvalid = output_3_axis_tvalid_reg; -assign output_3_axis_tlast = output_axis_tlast_reg; -assign output_3_axis_tid = ID_ENABLE ? output_axis_tid_reg : {ID_WIDTH{1'b0}}; -assign output_3_axis_tdest = DEST_ENABLE ? output_axis_tdest_reg : {DEST_WIDTH{1'b0}}; -assign output_3_axis_tuser = USER_ENABLE ? output_axis_tuser_int : {USER_WIDTH{1'b0}}; - -// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input) -assign output_axis_tready_int_early = current_output_tready | (~temp_axis_tvalid_reg & (~current_output_tvalid | ~output_axis_tvalid_int)); - -always @* begin - // transfer sink ready state to source - output_0_axis_tvalid_next = output_0_axis_tvalid_reg; - output_1_axis_tvalid_next = output_1_axis_tvalid_reg; - output_2_axis_tvalid_next = output_2_axis_tvalid_reg; - output_3_axis_tvalid_next = output_3_axis_tvalid_reg; - temp_axis_tvalid_next = temp_axis_tvalid_reg; - - store_axis_int_to_output = 1'b0; - store_axis_int_to_temp = 1'b0; - store_axis_temp_to_output = 1'b0; - - if (output_axis_tready_int_reg) begin - // input is ready - if (current_output_tready | ~current_output_tvalid) begin - // output is ready or currently not valid, transfer data to output - output_0_axis_tvalid_next = output_axis_tvalid_int & (select_reg == 2'd0); - output_1_axis_tvalid_next = output_axis_tvalid_int & (select_reg == 2'd1); - output_2_axis_tvalid_next = output_axis_tvalid_int & (select_reg == 2'd2); - output_3_axis_tvalid_next = output_axis_tvalid_int & (select_reg == 2'd3); - store_axis_int_to_output = 1'b1; - end else begin - // output is not ready, store input in temp - temp_axis_tvalid_next = output_axis_tvalid_int; - store_axis_int_to_temp = 1'b1; - end - end else if (current_output_tready) begin - // input is not ready, but output is ready - output_0_axis_tvalid_next = temp_axis_tvalid_reg & (select_reg == 2'd0); - output_1_axis_tvalid_next = temp_axis_tvalid_reg & (select_reg == 2'd1); - output_2_axis_tvalid_next = temp_axis_tvalid_reg & (select_reg == 2'd2); - output_3_axis_tvalid_next = temp_axis_tvalid_reg & (select_reg == 2'd3); - temp_axis_tvalid_next = 1'b0; - store_axis_temp_to_output = 1'b1; - end -end - -always @(posedge clk) begin - if (rst) begin - output_0_axis_tvalid_reg <= 1'b0; - output_1_axis_tvalid_reg <= 1'b0; - output_2_axis_tvalid_reg <= 1'b0; - output_3_axis_tvalid_reg <= 1'b0; - output_axis_tready_int_reg <= 1'b0; - temp_axis_tvalid_reg <= 1'b0; - end else begin - output_0_axis_tvalid_reg <= output_0_axis_tvalid_next; - output_1_axis_tvalid_reg <= output_1_axis_tvalid_next; - output_2_axis_tvalid_reg <= output_2_axis_tvalid_next; - output_3_axis_tvalid_reg <= output_3_axis_tvalid_next; - output_axis_tready_int_reg <= output_axis_tready_int_early; - temp_axis_tvalid_reg <= temp_axis_tvalid_next; - end - - // datapath - if (store_axis_int_to_output) begin - output_axis_tdata_reg <= output_axis_tdata_int; - output_axis_tkeep_reg <= output_axis_tkeep_int; - output_axis_tlast_reg <= output_axis_tlast_int; - output_axis_tid_reg <= output_axis_tid_int; - output_axis_tdest_reg <= output_axis_tdest_int; - output_axis_tuser_reg <= output_axis_tuser_int; - end else if (store_axis_temp_to_output) begin - output_axis_tdata_reg <= temp_axis_tdata_reg; - output_axis_tkeep_reg <= temp_axis_tkeep_reg; - output_axis_tlast_reg <= temp_axis_tlast_reg; - output_axis_tid_reg <= temp_axis_tid_reg; - output_axis_tdest_reg <= temp_axis_tdest_reg; - output_axis_tuser_reg <= temp_axis_tuser_reg; - end - - if (store_axis_int_to_temp) begin - temp_axis_tdata_reg <= output_axis_tdata_int; - temp_axis_tkeep_reg <= output_axis_tkeep_int; - temp_axis_tlast_reg <= output_axis_tlast_int; - temp_axis_tid_reg <= output_axis_tid_int; - temp_axis_tdest_reg <= output_axis_tdest_int; - temp_axis_tuser_reg <= output_axis_tuser_int; - end -end - -endmodule diff --git a/tb/test_axis_demux_4.py b/tb/test_axis_demux_4.py index 1c481a82b..b6b780c7b 100755 --- a/tb/test_axis_demux_4.py +++ b/tb/test_axis_demux_4.py @@ -27,9 +27,10 @@ from myhdl import * import os import axis_ep +import math -module = 'axis_demux_4' -testbench = 'test_%s' % module +module = 'axis_demux' +testbench = 'test_%s_4' % module srcs = [] @@ -43,6 +44,7 @@ build_cmd = "iverilog -o %s.vvp %s" % (testbench, src) def bench(): # Parameters + M_COUNT = 4 DATA_WIDTH = 8 KEEP_ENABLE = (DATA_WIDTH>8) KEEP_WIDTH = (DATA_WIDTH/8) @@ -58,145 +60,85 @@ def bench(): rst = Signal(bool(0)) current_test = Signal(intbv(0)[8:]) - input_axis_tdata = Signal(intbv(0)[DATA_WIDTH:]) - input_axis_tkeep = Signal(intbv(1)[KEEP_WIDTH:]) - input_axis_tvalid = Signal(bool(0)) - input_axis_tlast = Signal(bool(0)) - input_axis_tid = Signal(intbv(0)[ID_WIDTH:]) - input_axis_tdest = Signal(intbv(0)[DEST_WIDTH:]) - input_axis_tuser = Signal(intbv(0)[USER_WIDTH:]) + s_axis_tdata = Signal(intbv(0)[DATA_WIDTH:]) + s_axis_tkeep = Signal(intbv(1)[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:]) - output_0_axis_tready = Signal(bool(0)) - output_1_axis_tready = Signal(bool(0)) - output_2_axis_tready = Signal(bool(0)) - output_3_axis_tready = Signal(bool(0)) + m_axis_tready_list = [Signal(bool(0)) for i in range(M_COUNT)] + + m_axis_tready = ConcatSignal(*reversed(m_axis_tready_list)) enable = Signal(bool(0)) - select = Signal(intbv(0)[2:]) + drop = Signal(bool(0)) + select = Signal(intbv(0)[math.ceil(math.log(M_COUNT, 2)):]) # Outputs - input_axis_tready = Signal(bool(0)) + s_axis_tready = Signal(bool(0)) - output_0_axis_tdata = Signal(intbv(0)[DATA_WIDTH:]) - output_0_axis_tkeep = Signal(intbv(1)[KEEP_WIDTH:]) - output_0_axis_tvalid = Signal(bool(0)) - output_0_axis_tlast = Signal(bool(0)) - output_0_axis_tid = Signal(intbv(0)[ID_WIDTH:]) - output_0_axis_tdest = Signal(intbv(0)[DEST_WIDTH:]) - output_0_axis_tuser = Signal(intbv(0)[USER_WIDTH:]) - output_1_axis_tdata = Signal(intbv(0)[DATA_WIDTH:]) - output_1_axis_tkeep = Signal(intbv(1)[KEEP_WIDTH:]) - output_1_axis_tvalid = Signal(bool(0)) - output_1_axis_tlast = Signal(bool(0)) - output_1_axis_tid = Signal(intbv(0)[ID_WIDTH:]) - output_1_axis_tdest = Signal(intbv(0)[DEST_WIDTH:]) - output_1_axis_tuser = Signal(intbv(0)[USER_WIDTH:]) - output_2_axis_tdata = Signal(intbv(0)[DATA_WIDTH:]) - output_2_axis_tkeep = Signal(intbv(1)[KEEP_WIDTH:]) - output_2_axis_tvalid = Signal(bool(0)) - output_2_axis_tlast = Signal(bool(0)) - output_2_axis_tid = Signal(intbv(0)[ID_WIDTH:]) - output_2_axis_tdest = Signal(intbv(0)[DEST_WIDTH:]) - output_2_axis_tuser = Signal(intbv(0)[USER_WIDTH:]) - output_3_axis_tdata = Signal(intbv(0)[DATA_WIDTH:]) - output_3_axis_tkeep = Signal(intbv(1)[KEEP_WIDTH:]) - output_3_axis_tvalid = Signal(bool(0)) - output_3_axis_tlast = Signal(bool(0)) - output_3_axis_tid = Signal(intbv(0)[ID_WIDTH:]) - output_3_axis_tdest = Signal(intbv(0)[DEST_WIDTH:]) - output_3_axis_tuser = Signal(intbv(0)[USER_WIDTH:]) + m_axis_tdata = Signal(intbv(0)[M_COUNT*DATA_WIDTH:]) + m_axis_tkeep = Signal(intbv(0xf)[M_COUNT*KEEP_WIDTH:]) + m_axis_tvalid = Signal(intbv(0)[M_COUNT:]) + m_axis_tlast = Signal(intbv(0)[M_COUNT:]) + m_axis_tid = Signal(intbv(0)[M_COUNT*ID_WIDTH:]) + m_axis_tdest = Signal(intbv(0)[M_COUNT*DEST_WIDTH:]) + m_axis_tuser = Signal(intbv(0)[M_COUNT*USER_WIDTH:]) + + m_axis_tdata_list = [m_axis_tdata((i+1)*DATA_WIDTH, i*DATA_WIDTH) for i in range(M_COUNT)] + m_axis_tkeep_list = [m_axis_tkeep((i+1)*KEEP_WIDTH, i*KEEP_WIDTH) for i in range(M_COUNT)] + m_axis_tvalid_list = [m_axis_tvalid(i) for i in range(M_COUNT)] + m_axis_tlast_list = [m_axis_tlast(i) for i in range(M_COUNT)] + m_axis_tid_list = [m_axis_tid((i+1)*ID_WIDTH, i*ID_WIDTH) for i in range(M_COUNT)] + m_axis_tdest_list = [m_axis_tdest((i+1)*DEST_WIDTH, i*DEST_WIDTH) for i in range(M_COUNT)] + m_axis_tuser_list = [m_axis_tuser((i+1)*USER_WIDTH, i*USER_WIDTH) for i in range(M_COUNT)] # sources and sinks source_pause = Signal(bool(0)) - sink_0_pause = Signal(bool(0)) - sink_1_pause = Signal(bool(0)) - sink_2_pause = Signal(bool(0)) - sink_3_pause = Signal(bool(0)) + sink_pause_list = [] + sink_list = [] + sink_logic_list = [] source = axis_ep.AXIStreamSource() source_logic = source.create_logic( clk, rst, - tdata=input_axis_tdata, - tkeep=input_axis_tkeep, - tvalid=input_axis_tvalid, - tready=input_axis_tready, - tlast=input_axis_tlast, - tid=input_axis_tid, - tdest=input_axis_tdest, - tuser=input_axis_tuser, + 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_0 = axis_ep.AXIStreamSink() + for k in range(M_COUNT): + s = axis_ep.AXIStreamSink() + p = Signal(bool(0)) - sink_0_logic = sink_0.create_logic( - clk, - rst, - tdata=output_0_axis_tdata, - tkeep=output_0_axis_tkeep, - tvalid=output_0_axis_tvalid, - tready=output_0_axis_tready, - tlast=output_0_axis_tlast, - tid=output_0_axis_tid, - tdest=output_0_axis_tdest, - tuser=output_0_axis_tuser, - pause=sink_0_pause, - name='sink_0' - ) + sink_list.append(s) + sink_pause_list.append(p) - sink_1 = axis_ep.AXIStreamSink() - - sink_1_logic = sink_1.create_logic( - clk, - rst, - tdata=output_1_axis_tdata, - tkeep=output_1_axis_tkeep, - tvalid=output_1_axis_tvalid, - tready=output_1_axis_tready, - tlast=output_1_axis_tlast, - tid=output_1_axis_tid, - tdest=output_1_axis_tdest, - tuser=output_1_axis_tuser, - pause=sink_1_pause, - name='sink_1' - ) - - sink_2 = axis_ep.AXIStreamSink() - - sink_2_logic = sink_2.create_logic( - clk, - rst, - tdata=output_2_axis_tdata, - tkeep=output_2_axis_tkeep, - tvalid=output_2_axis_tvalid, - tready=output_2_axis_tready, - tlast=output_2_axis_tlast, - tid=output_2_axis_tid, - tdest=output_2_axis_tdest, - tuser=output_2_axis_tuser, - pause=sink_2_pause, - name='sink_2' - ) - - sink_3 = axis_ep.AXIStreamSink() - - sink_3_logic = sink_3.create_logic( - clk, - rst, - tdata=output_3_axis_tdata, - tkeep=output_3_axis_tkeep, - tvalid=output_3_axis_tvalid, - tready=output_3_axis_tready, - tlast=output_3_axis_tlast, - tid=output_3_axis_tid, - tdest=output_3_axis_tdest, - tuser=output_3_axis_tuser, - pause=sink_3_pause, - name='sink_3' - ) + sink_logic_list.append(s.create_logic( + clk, + rst, + tdata=m_axis_tdata_list[k], + tkeep=m_axis_tkeep_list[k], + tvalid=m_axis_tvalid_list[k], + tready=m_axis_tready_list[k], + tlast=m_axis_tlast_list[k], + tid=m_axis_tid_list[k], + tdest=m_axis_tdest_list[k], + tuser=m_axis_tuser_list[k], + pause=p, + name='sink_%d' % k + )) # DUT if os.system(build_cmd): @@ -208,49 +150,26 @@ def bench(): rst=rst, current_test=current_test, - input_axis_tdata=input_axis_tdata, - input_axis_tkeep=input_axis_tkeep, - input_axis_tvalid=input_axis_tvalid, - input_axis_tready=input_axis_tready, - input_axis_tlast=input_axis_tlast, - input_axis_tid=input_axis_tid, - input_axis_tdest=input_axis_tdest, - input_axis_tuser=input_axis_tuser, + 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, - output_0_axis_tdata=output_0_axis_tdata, - output_0_axis_tkeep=output_0_axis_tkeep, - output_0_axis_tvalid=output_0_axis_tvalid, - output_0_axis_tready=output_0_axis_tready, - output_0_axis_tlast=output_0_axis_tlast, - output_0_axis_tid=output_0_axis_tid, - output_0_axis_tdest=output_0_axis_tdest, - output_0_axis_tuser=output_0_axis_tuser, - output_1_axis_tdata=output_1_axis_tdata, - output_1_axis_tkeep=output_1_axis_tkeep, - output_1_axis_tvalid=output_1_axis_tvalid, - output_1_axis_tready=output_1_axis_tready, - output_1_axis_tlast=output_1_axis_tlast, - output_1_axis_tid=output_1_axis_tid, - output_1_axis_tdest=output_1_axis_tdest, - output_1_axis_tuser=output_1_axis_tuser, - output_2_axis_tdata=output_2_axis_tdata, - output_2_axis_tkeep=output_2_axis_tkeep, - output_2_axis_tvalid=output_2_axis_tvalid, - output_2_axis_tready=output_2_axis_tready, - output_2_axis_tlast=output_2_axis_tlast, - output_2_axis_tid=output_2_axis_tid, - output_2_axis_tdest=output_2_axis_tdest, - output_2_axis_tuser=output_2_axis_tuser, - output_3_axis_tdata=output_3_axis_tdata, - output_3_axis_tkeep=output_3_axis_tkeep, - output_3_axis_tvalid=output_3_axis_tvalid, - output_3_axis_tready=output_3_axis_tready, - output_3_axis_tlast=output_3_axis_tlast, - output_3_axis_tid=output_3_axis_tid, - output_3_axis_tdest=output_3_axis_tdest, - output_3_axis_tuser=output_3_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, enable=enable, + drop=drop, select=select ) @@ -271,6 +190,7 @@ def bench(): yield clk.posedge enable.next = True + drop.next = False yield clk.posedge print("test 1: select port 0") @@ -289,8 +209,8 @@ def bench(): source.send(test_frame) - yield sink_0.wait() - rx_frame = sink_0.recv() + yield sink_list[0].wait() + rx_frame = sink_list[0].recv() assert rx_frame == test_frame @@ -313,8 +233,8 @@ def bench(): source.send(test_frame) - yield sink_1.wait() - rx_frame = sink_1.recv() + yield sink_list[1].wait() + rx_frame = sink_list[1].recv() assert rx_frame == test_frame @@ -346,13 +266,13 @@ def bench(): source.send(test_frame1) source.send(test_frame2) - yield sink_0.wait() - rx_frame = sink_0.recv() + yield sink_list[0].wait() + rx_frame = sink_list[0].recv() assert rx_frame == test_frame1 - yield sink_0.wait() - rx_frame = sink_0.recv() + yield sink_list[0].wait() + rx_frame = sink_list[0].recv() assert rx_frame == test_frame2 @@ -385,17 +305,17 @@ def bench(): source.send(test_frame2) yield clk.posedge - while input_axis_tvalid: + while s_axis_tvalid: yield clk.posedge select.next = 2 - yield sink_1.wait() - rx_frame = sink_1.recv() + yield sink_list[1].wait() + rx_frame = sink_list[1].recv() assert rx_frame == test_frame1 - yield sink_2.wait() - rx_frame = sink_2.recv() + yield sink_list[2].wait() + rx_frame = sink_list[2].recv() assert rx_frame == test_frame2 @@ -428,7 +348,7 @@ def bench(): source.send(test_frame2) yield clk.posedge - while input_axis_tvalid: + while s_axis_tvalid: source_pause.next = True yield clk.posedge yield clk.posedge @@ -437,13 +357,13 @@ def bench(): yield clk.posedge select.next = 2 - yield sink_1.wait() - rx_frame = sink_1.recv() + yield sink_list[1].wait() + rx_frame = sink_list[1].recv() assert rx_frame == test_frame1 - yield sink_2.wait() - rx_frame = sink_2.recv() + yield sink_list[2].wait() + rx_frame = sink_list[2].recv() assert rx_frame == test_frame2 @@ -476,33 +396,90 @@ def bench(): source.send(test_frame2) yield clk.posedge - while input_axis_tvalid: - sink_0_pause.next = True - sink_1_pause.next = True - sink_2_pause.next = True - sink_3_pause.next = True + while s_axis_tvalid: + sink_pause_list[0].next = True + sink_pause_list[1].next = True + sink_pause_list[2].next = True + sink_pause_list[3].next = True yield clk.posedge yield clk.posedge yield clk.posedge - sink_0_pause.next = False - sink_1_pause.next = False - sink_2_pause.next = False - sink_3_pause.next = False + sink_pause_list[0].next = False + sink_pause_list[1].next = False + sink_pause_list[2].next = False + sink_pause_list[3].next = False yield clk.posedge select.next = 2 - yield sink_1.wait() - rx_frame = sink_1.recv() + yield sink_list[1].wait() + rx_frame = sink_list[1].recv() assert rx_frame == test_frame1 - yield sink_2.wait() - rx_frame = sink_2.recv() + yield sink_list[2].wait() + rx_frame = sink_list[2].recv() assert rx_frame == test_frame2 yield delay(100) + yield clk.posedge + print("test 7: enable") + current_test.next = 7 + + enable.next = False + select.next = 0 + + 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', + id=7, + dest=1 + ) + + source.send(test_frame) + + yield delay(500) + + assert sink_list[0].empty() + + enable.next = True + + yield sink_list[0].wait() + rx_frame = sink_list[0].recv() + + assert rx_frame == test_frame + + yield delay(100) + + yield clk.posedge + print("test 8: drop") + current_test.next = 8 + + drop.next = True + select.next = 0 + + 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', + id=8, + dest=1 + ) + + source.send(test_frame) + + yield delay(500) + + assert sink_list[0].empty() + + drop.next = False + + yield delay(100) + raise StopSimulation return instances() diff --git a/tb/test_axis_demux_4.v b/tb/test_axis_demux_4.v index 99d09f115..b58507609 100644 --- a/tb/test_axis_demux_4.v +++ b/tb/test_axis_demux_4.v @@ -27,11 +27,12 @@ THE SOFTWARE. `timescale 1ns / 1ps /* - * Testbench for axis_demux_4 + * Testbench for axis_demux */ module test_axis_demux_4; // Parameters +parameter M_COUNT = 4; parameter DATA_WIDTH = 8; parameter KEEP_ENABLE = (DATA_WIDTH>8); parameter KEEP_WIDTH = (DATA_WIDTH/8); @@ -47,53 +48,30 @@ reg clk = 0; reg rst = 0; reg [7:0] current_test = 0; -reg [DATA_WIDTH-1:0] input_axis_tdata = 0; -reg [KEEP_WIDTH-1:0] input_axis_tkeep = 0; -reg input_axis_tvalid = 0; -reg input_axis_tlast = 0; -reg [ID_WIDTH-1:0] input_axis_tid = 0; -reg [DEST_WIDTH-1:0] input_axis_tdest = 0; -reg [USER_WIDTH-1:0] input_axis_tuser = 0; +reg [DATA_WIDTH-1:0] s_axis_tdata = 0; +reg [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 output_0_axis_tready = 0; -reg output_1_axis_tready = 0; -reg output_2_axis_tready = 0; -reg output_3_axis_tready = 0; +reg [M_COUNT-1:0] m_axis_tready = 0; reg enable = 0; -reg [1:0] select = 0; +reg drop = 0; +reg [$clog2(M_COUNT)-1:0] select = 0; // Outputs -wire input_axis_tready; +wire s_axis_tready; -wire [DATA_WIDTH-1:0] output_0_axis_tdata; -wire [KEEP_WIDTH-1:0] output_0_axis_tkeep; -wire output_0_axis_tvalid; -wire output_0_axis_tlast; -wire [ID_WIDTH-1:0] output_0_axis_tid; -wire [DEST_WIDTH-1:0] output_0_axis_tdest; -wire [USER_WIDTH-1:0] output_0_axis_tuser; -wire [DATA_WIDTH-1:0] output_1_axis_tdata; -wire [KEEP_WIDTH-1:0] output_1_axis_tkeep; -wire output_1_axis_tvalid; -wire output_1_axis_tlast; -wire [ID_WIDTH-1:0] output_1_axis_tid; -wire [DEST_WIDTH-1:0] output_1_axis_tdest; -wire [USER_WIDTH-1:0] output_1_axis_tuser; -wire [DATA_WIDTH-1:0] output_2_axis_tdata; -wire [KEEP_WIDTH-1:0] output_2_axis_tkeep; -wire output_2_axis_tvalid; -wire output_2_axis_tlast; -wire [ID_WIDTH-1:0] output_2_axis_tid; -wire [DEST_WIDTH-1:0] output_2_axis_tdest; -wire [USER_WIDTH-1:0] output_2_axis_tuser; -wire [DATA_WIDTH-1:0] output_3_axis_tdata; -wire [KEEP_WIDTH-1:0] output_3_axis_tkeep; -wire output_3_axis_tvalid; -wire output_3_axis_tlast; -wire [ID_WIDTH-1:0] output_3_axis_tid; -wire [DEST_WIDTH-1:0] output_3_axis_tdest; -wire [USER_WIDTH-1:0] output_3_axis_tuser; +wire [M_COUNT*DATA_WIDTH-1:0] m_axis_tdata; +wire [M_COUNT*KEEP_WIDTH-1:0] m_axis_tkeep; +wire [M_COUNT-1:0] m_axis_tvalid; +wire [M_COUNT-1:0] m_axis_tlast; +wire [M_COUNT*ID_WIDTH-1:0] m_axis_tid; +wire [M_COUNT*DEST_WIDTH-1:0] m_axis_tdest; +wire [M_COUNT*USER_WIDTH-1:0] m_axis_tuser; initial begin // myhdl integration @@ -101,50 +79,27 @@ initial begin clk, rst, current_test, - input_axis_tdata, - input_axis_tkeep, - input_axis_tvalid, - input_axis_tlast, - input_axis_tid, - input_axis_tdest, - input_axis_tuser, - output_0_axis_tready, - output_1_axis_tready, - output_2_axis_tready, - output_3_axis_tready, + s_axis_tdata, + s_axis_tkeep, + s_axis_tvalid, + s_axis_tlast, + s_axis_tid, + s_axis_tdest, + s_axis_tuser, + m_axis_tready, enable, + drop, select ); $to_myhdl( - input_axis_tready, - output_0_axis_tdata, - output_0_axis_tkeep, - output_0_axis_tvalid, - output_0_axis_tlast, - output_0_axis_tid, - output_0_axis_tdest, - output_0_axis_tuser, - output_1_axis_tdata, - output_1_axis_tkeep, - output_1_axis_tvalid, - output_1_axis_tlast, - output_1_axis_tid, - output_1_axis_tdest, - output_1_axis_tuser, - output_2_axis_tdata, - output_2_axis_tkeep, - output_2_axis_tvalid, - output_2_axis_tlast, - output_2_axis_tid, - output_2_axis_tdest, - output_2_axis_tuser, - output_3_axis_tdata, - output_3_axis_tkeep, - output_3_axis_tvalid, - output_3_axis_tlast, - output_3_axis_tid, - output_3_axis_tdest, - output_3_axis_tuser + 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 @@ -152,7 +107,8 @@ initial begin $dumpvars(0, test_axis_demux_4); end -axis_demux_4 #( +axis_demux #( + .M_COUNT(M_COUNT), .DATA_WIDTH(DATA_WIDTH), .KEEP_ENABLE(KEEP_ENABLE), .KEEP_WIDTH(KEEP_WIDTH), @@ -167,49 +123,26 @@ UUT ( .clk(clk), .rst(rst), // AXI input - .input_axis_tdata(input_axis_tdata), - .input_axis_tkeep(input_axis_tkeep), - .input_axis_tvalid(input_axis_tvalid), - .input_axis_tready(input_axis_tready), - .input_axis_tlast(input_axis_tlast), - .input_axis_tid(input_axis_tid), - .input_axis_tdest(input_axis_tdest), - .input_axis_tuser(input_axis_tuser), + .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 outputs - .output_0_axis_tdata(output_0_axis_tdata), - .output_0_axis_tkeep(output_0_axis_tkeep), - .output_0_axis_tvalid(output_0_axis_tvalid), - .output_0_axis_tready(output_0_axis_tready), - .output_0_axis_tlast(output_0_axis_tlast), - .output_0_axis_tid(output_0_axis_tid), - .output_0_axis_tdest(output_0_axis_tdest), - .output_0_axis_tuser(output_0_axis_tuser), - .output_1_axis_tdata(output_1_axis_tdata), - .output_1_axis_tkeep(output_1_axis_tkeep), - .output_1_axis_tvalid(output_1_axis_tvalid), - .output_1_axis_tready(output_1_axis_tready), - .output_1_axis_tlast(output_1_axis_tlast), - .output_1_axis_tid(output_1_axis_tid), - .output_1_axis_tdest(output_1_axis_tdest), - .output_1_axis_tuser(output_1_axis_tuser), - .output_2_axis_tdata(output_2_axis_tdata), - .output_2_axis_tkeep(output_2_axis_tkeep), - .output_2_axis_tvalid(output_2_axis_tvalid), - .output_2_axis_tready(output_2_axis_tready), - .output_2_axis_tlast(output_2_axis_tlast), - .output_2_axis_tid(output_2_axis_tid), - .output_2_axis_tdest(output_2_axis_tdest), - .output_2_axis_tuser(output_2_axis_tuser), - .output_3_axis_tdata(output_3_axis_tdata), - .output_3_axis_tkeep(output_3_axis_tkeep), - .output_3_axis_tvalid(output_3_axis_tvalid), - .output_3_axis_tready(output_3_axis_tready), - .output_3_axis_tlast(output_3_axis_tlast), - .output_3_axis_tid(output_3_axis_tid), - .output_3_axis_tdest(output_3_axis_tdest), - .output_3_axis_tuser(output_3_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), // Control .enable(enable), + .drop(drop), .select(select) ); diff --git a/tb/test_axis_demux_4_64.py b/tb/test_axis_demux_4_64.py index ea00eced1..5c91bc39d 100755 --- a/tb/test_axis_demux_4_64.py +++ b/tb/test_axis_demux_4_64.py @@ -27,9 +27,10 @@ from myhdl import * import os import axis_ep +import math -module = 'axis_demux_4' -testbench = 'test_%s_64' % module +module = 'axis_demux' +testbench = 'test_%s_4_64' % module srcs = [] @@ -43,6 +44,7 @@ build_cmd = "iverilog -o %s.vvp %s" % (testbench, src) def bench(): # Parameters + M_COUNT = 4 DATA_WIDTH = 64 KEEP_ENABLE = (DATA_WIDTH>8) KEEP_WIDTH = (DATA_WIDTH/8) @@ -58,145 +60,85 @@ def bench(): rst = Signal(bool(0)) current_test = Signal(intbv(0)[8:]) - input_axis_tdata = Signal(intbv(0)[DATA_WIDTH:]) - input_axis_tkeep = Signal(intbv(1)[KEEP_WIDTH:]) - input_axis_tvalid = Signal(bool(0)) - input_axis_tlast = Signal(bool(0)) - input_axis_tid = Signal(intbv(0)[ID_WIDTH:]) - input_axis_tdest = Signal(intbv(0)[DEST_WIDTH:]) - input_axis_tuser = Signal(intbv(0)[USER_WIDTH:]) + s_axis_tdata = Signal(intbv(0)[DATA_WIDTH:]) + s_axis_tkeep = Signal(intbv(1)[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:]) - output_0_axis_tready = Signal(bool(0)) - output_1_axis_tready = Signal(bool(0)) - output_2_axis_tready = Signal(bool(0)) - output_3_axis_tready = Signal(bool(0)) + m_axis_tready_list = [Signal(bool(0)) for i in range(M_COUNT)] + + m_axis_tready = ConcatSignal(*reversed(m_axis_tready_list)) enable = Signal(bool(0)) - select = Signal(intbv(0)[2:]) + drop = Signal(bool(0)) + select = Signal(intbv(0)[math.ceil(math.log(M_COUNT, 2)):]) # Outputs - input_axis_tready = Signal(bool(0)) + s_axis_tready = Signal(bool(0)) - output_0_axis_tdata = Signal(intbv(0)[DATA_WIDTH:]) - output_0_axis_tkeep = Signal(intbv(1)[KEEP_WIDTH:]) - output_0_axis_tvalid = Signal(bool(0)) - output_0_axis_tlast = Signal(bool(0)) - output_0_axis_tid = Signal(intbv(0)[ID_WIDTH:]) - output_0_axis_tdest = Signal(intbv(0)[DEST_WIDTH:]) - output_0_axis_tuser = Signal(intbv(0)[USER_WIDTH:]) - output_1_axis_tdata = Signal(intbv(0)[DATA_WIDTH:]) - output_1_axis_tkeep = Signal(intbv(1)[KEEP_WIDTH:]) - output_1_axis_tvalid = Signal(bool(0)) - output_1_axis_tlast = Signal(bool(0)) - output_1_axis_tid = Signal(intbv(0)[ID_WIDTH:]) - output_1_axis_tdest = Signal(intbv(0)[DEST_WIDTH:]) - output_1_axis_tuser = Signal(intbv(0)[USER_WIDTH:]) - output_2_axis_tdata = Signal(intbv(0)[DATA_WIDTH:]) - output_2_axis_tkeep = Signal(intbv(1)[KEEP_WIDTH:]) - output_2_axis_tvalid = Signal(bool(0)) - output_2_axis_tlast = Signal(bool(0)) - output_2_axis_tid = Signal(intbv(0)[ID_WIDTH:]) - output_2_axis_tdest = Signal(intbv(0)[DEST_WIDTH:]) - output_2_axis_tuser = Signal(intbv(0)[USER_WIDTH:]) - output_3_axis_tdata = Signal(intbv(0)[DATA_WIDTH:]) - output_3_axis_tkeep = Signal(intbv(1)[KEEP_WIDTH:]) - output_3_axis_tvalid = Signal(bool(0)) - output_3_axis_tlast = Signal(bool(0)) - output_3_axis_tid = Signal(intbv(0)[ID_WIDTH:]) - output_3_axis_tdest = Signal(intbv(0)[DEST_WIDTH:]) - output_3_axis_tuser = Signal(intbv(0)[USER_WIDTH:]) + m_axis_tdata = Signal(intbv(0)[M_COUNT*DATA_WIDTH:]) + m_axis_tkeep = Signal(intbv(0xf)[M_COUNT*KEEP_WIDTH:]) + m_axis_tvalid = Signal(intbv(0)[M_COUNT:]) + m_axis_tlast = Signal(intbv(0)[M_COUNT:]) + m_axis_tid = Signal(intbv(0)[M_COUNT*ID_WIDTH:]) + m_axis_tdest = Signal(intbv(0)[M_COUNT*DEST_WIDTH:]) + m_axis_tuser = Signal(intbv(0)[M_COUNT*USER_WIDTH:]) + + m_axis_tdata_list = [m_axis_tdata((i+1)*DATA_WIDTH, i*DATA_WIDTH) for i in range(M_COUNT)] + m_axis_tkeep_list = [m_axis_tkeep((i+1)*KEEP_WIDTH, i*KEEP_WIDTH) for i in range(M_COUNT)] + m_axis_tvalid_list = [m_axis_tvalid(i) for i in range(M_COUNT)] + m_axis_tlast_list = [m_axis_tlast(i) for i in range(M_COUNT)] + m_axis_tid_list = [m_axis_tid((i+1)*ID_WIDTH, i*ID_WIDTH) for i in range(M_COUNT)] + m_axis_tdest_list = [m_axis_tdest((i+1)*DEST_WIDTH, i*DEST_WIDTH) for i in range(M_COUNT)] + m_axis_tuser_list = [m_axis_tuser((i+1)*USER_WIDTH, i*USER_WIDTH) for i in range(M_COUNT)] # sources and sinks source_pause = Signal(bool(0)) - sink_0_pause = Signal(bool(0)) - sink_1_pause = Signal(bool(0)) - sink_2_pause = Signal(bool(0)) - sink_3_pause = Signal(bool(0)) + sink_pause_list = [] + sink_list = [] + sink_logic_list = [] source = axis_ep.AXIStreamSource() source_logic = source.create_logic( clk, rst, - tdata=input_axis_tdata, - tkeep=input_axis_tkeep, - tvalid=input_axis_tvalid, - tready=input_axis_tready, - tlast=input_axis_tlast, - tid=input_axis_tid, - tdest=input_axis_tdest, - tuser=input_axis_tuser, + 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_0 = axis_ep.AXIStreamSink() + for k in range(M_COUNT): + s = axis_ep.AXIStreamSink() + p = Signal(bool(0)) - sink_0_logic = sink_0.create_logic( - clk, - rst, - tdata=output_0_axis_tdata, - tkeep=output_0_axis_tkeep, - tvalid=output_0_axis_tvalid, - tready=output_0_axis_tready, - tlast=output_0_axis_tlast, - tid=output_0_axis_tid, - tdest=output_0_axis_tdest, - tuser=output_0_axis_tuser, - pause=sink_0_pause, - name='sink_0' - ) + sink_list.append(s) + sink_pause_list.append(p) - sink_1 = axis_ep.AXIStreamSink() - - sink_1_logic = sink_1.create_logic( - clk, - rst, - tdata=output_1_axis_tdata, - tkeep=output_1_axis_tkeep, - tvalid=output_1_axis_tvalid, - tready=output_1_axis_tready, - tlast=output_1_axis_tlast, - tid=output_1_axis_tid, - tdest=output_1_axis_tdest, - tuser=output_1_axis_tuser, - pause=sink_1_pause, - name='sink_1' - ) - - sink_2 = axis_ep.AXIStreamSink() - - sink_2_logic = sink_2.create_logic( - clk, - rst, - tdata=output_2_axis_tdata, - tkeep=output_2_axis_tkeep, - tvalid=output_2_axis_tvalid, - tready=output_2_axis_tready, - tlast=output_2_axis_tlast, - tid=output_2_axis_tid, - tdest=output_2_axis_tdest, - tuser=output_2_axis_tuser, - pause=sink_2_pause, - name='sink_2' - ) - - sink_3 = axis_ep.AXIStreamSink() - - sink_3_logic = sink_3.create_logic( - clk, - rst, - tdata=output_3_axis_tdata, - tkeep=output_3_axis_tkeep, - tvalid=output_3_axis_tvalid, - tready=output_3_axis_tready, - tlast=output_3_axis_tlast, - tid=output_3_axis_tid, - tdest=output_3_axis_tdest, - tuser=output_3_axis_tuser, - pause=sink_3_pause, - name='sink_3' - ) + sink_logic_list.append(s.create_logic( + clk, + rst, + tdata=m_axis_tdata_list[k], + tkeep=m_axis_tkeep_list[k], + tvalid=m_axis_tvalid_list[k], + tready=m_axis_tready_list[k], + tlast=m_axis_tlast_list[k], + tid=m_axis_tid_list[k], + tdest=m_axis_tdest_list[k], + tuser=m_axis_tuser_list[k], + pause=p, + name='sink_%d' % k + )) # DUT if os.system(build_cmd): @@ -208,49 +150,26 @@ def bench(): rst=rst, current_test=current_test, - input_axis_tdata=input_axis_tdata, - input_axis_tkeep=input_axis_tkeep, - input_axis_tvalid=input_axis_tvalid, - input_axis_tready=input_axis_tready, - input_axis_tlast=input_axis_tlast, - input_axis_tid=input_axis_tid, - input_axis_tdest=input_axis_tdest, - input_axis_tuser=input_axis_tuser, + 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, - output_0_axis_tdata=output_0_axis_tdata, - output_0_axis_tkeep=output_0_axis_tkeep, - output_0_axis_tvalid=output_0_axis_tvalid, - output_0_axis_tready=output_0_axis_tready, - output_0_axis_tlast=output_0_axis_tlast, - output_0_axis_tid=output_0_axis_tid, - output_0_axis_tdest=output_0_axis_tdest, - output_0_axis_tuser=output_0_axis_tuser, - output_1_axis_tdata=output_1_axis_tdata, - output_1_axis_tkeep=output_1_axis_tkeep, - output_1_axis_tvalid=output_1_axis_tvalid, - output_1_axis_tready=output_1_axis_tready, - output_1_axis_tlast=output_1_axis_tlast, - output_1_axis_tid=output_1_axis_tid, - output_1_axis_tdest=output_1_axis_tdest, - output_1_axis_tuser=output_1_axis_tuser, - output_2_axis_tdata=output_2_axis_tdata, - output_2_axis_tkeep=output_2_axis_tkeep, - output_2_axis_tvalid=output_2_axis_tvalid, - output_2_axis_tready=output_2_axis_tready, - output_2_axis_tlast=output_2_axis_tlast, - output_2_axis_tid=output_2_axis_tid, - output_2_axis_tdest=output_2_axis_tdest, - output_2_axis_tuser=output_2_axis_tuser, - output_3_axis_tdata=output_3_axis_tdata, - output_3_axis_tkeep=output_3_axis_tkeep, - output_3_axis_tvalid=output_3_axis_tvalid, - output_3_axis_tready=output_3_axis_tready, - output_3_axis_tlast=output_3_axis_tlast, - output_3_axis_tid=output_3_axis_tid, - output_3_axis_tdest=output_3_axis_tdest, - output_3_axis_tuser=output_3_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, enable=enable, + drop=drop, select=select ) @@ -271,6 +190,7 @@ def bench(): yield clk.posedge enable.next = True + drop.next = False yield clk.posedge print("test 1: select port 0") @@ -289,8 +209,8 @@ def bench(): source.send(test_frame) - yield sink_0.wait() - rx_frame = sink_0.recv() + yield sink_list[0].wait() + rx_frame = sink_list[0].recv() assert rx_frame == test_frame @@ -313,8 +233,8 @@ def bench(): source.send(test_frame) - yield sink_1.wait() - rx_frame = sink_1.recv() + yield sink_list[1].wait() + rx_frame = sink_list[1].recv() assert rx_frame == test_frame @@ -346,13 +266,13 @@ def bench(): source.send(test_frame1) source.send(test_frame2) - yield sink_0.wait() - rx_frame = sink_0.recv() + yield sink_list[0].wait() + rx_frame = sink_list[0].recv() assert rx_frame == test_frame1 - yield sink_0.wait() - rx_frame = sink_0.recv() + yield sink_list[0].wait() + rx_frame = sink_list[0].recv() assert rx_frame == test_frame2 @@ -385,17 +305,17 @@ def bench(): source.send(test_frame2) yield clk.posedge - while input_axis_tvalid: + while s_axis_tvalid: yield clk.posedge select.next = 2 - yield sink_1.wait() - rx_frame = sink_1.recv() + yield sink_list[1].wait() + rx_frame = sink_list[1].recv() assert rx_frame == test_frame1 - yield sink_2.wait() - rx_frame = sink_2.recv() + yield sink_list[2].wait() + rx_frame = sink_list[2].recv() assert rx_frame == test_frame2 @@ -428,7 +348,7 @@ def bench(): source.send(test_frame2) yield clk.posedge - while input_axis_tvalid: + while s_axis_tvalid: source_pause.next = True yield clk.posedge yield clk.posedge @@ -437,13 +357,13 @@ def bench(): yield clk.posedge select.next = 2 - yield sink_1.wait() - rx_frame = sink_1.recv() + yield sink_list[1].wait() + rx_frame = sink_list[1].recv() assert rx_frame == test_frame1 - yield sink_2.wait() - rx_frame = sink_2.recv() + yield sink_list[2].wait() + rx_frame = sink_list[2].recv() assert rx_frame == test_frame2 @@ -476,33 +396,90 @@ def bench(): source.send(test_frame2) yield clk.posedge - while input_axis_tvalid: - sink_0_pause.next = True - sink_1_pause.next = True - sink_2_pause.next = True - sink_3_pause.next = True + while s_axis_tvalid: + sink_pause_list[0].next = True + sink_pause_list[1].next = True + sink_pause_list[2].next = True + sink_pause_list[3].next = True yield clk.posedge yield clk.posedge yield clk.posedge - sink_0_pause.next = False - sink_1_pause.next = False - sink_2_pause.next = False - sink_3_pause.next = False + sink_pause_list[0].next = False + sink_pause_list[1].next = False + sink_pause_list[2].next = False + sink_pause_list[3].next = False yield clk.posedge select.next = 2 - yield sink_1.wait() - rx_frame = sink_1.recv() + yield sink_list[1].wait() + rx_frame = sink_list[1].recv() assert rx_frame == test_frame1 - yield sink_2.wait() - rx_frame = sink_2.recv() + yield sink_list[2].wait() + rx_frame = sink_list[2].recv() assert rx_frame == test_frame2 yield delay(100) + yield clk.posedge + print("test 7: enable") + current_test.next = 7 + + enable.next = False + select.next = 0 + + 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', + id=7, + dest=1 + ) + + source.send(test_frame) + + yield delay(100) + + assert sink_list[0].empty() + + enable.next = True + + yield sink_list[0].wait() + rx_frame = sink_list[0].recv() + + assert rx_frame == test_frame + + yield delay(100) + + yield clk.posedge + print("test 8: drop") + current_test.next = 8 + + drop.next = True + select.next = 0 + + 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', + id=8, + dest=1 + ) + + source.send(test_frame) + + yield delay(100) + + assert sink_list[0].empty() + + drop.next = False + + yield delay(100) + raise StopSimulation return instances() diff --git a/tb/test_axis_demux_4_64.v b/tb/test_axis_demux_4_64.v index 9eb86ec0c..2fb7d8894 100644 --- a/tb/test_axis_demux_4_64.v +++ b/tb/test_axis_demux_4_64.v @@ -27,11 +27,12 @@ THE SOFTWARE. `timescale 1ns / 1ps /* - * Testbench for axis_demux_4 + * Testbench for axis_demux */ module test_axis_demux_4_64; // Parameters +parameter M_COUNT = 4; parameter DATA_WIDTH = 64; parameter KEEP_ENABLE = (DATA_WIDTH>8); parameter KEEP_WIDTH = (DATA_WIDTH/8); @@ -47,53 +48,30 @@ reg clk = 0; reg rst = 0; reg [7:0] current_test = 0; -reg [DATA_WIDTH-1:0] input_axis_tdata = 0; -reg [KEEP_WIDTH-1:0] input_axis_tkeep = 0; -reg input_axis_tvalid = 0; -reg input_axis_tlast = 0; -reg [ID_WIDTH-1:0] input_axis_tid = 0; -reg [DEST_WIDTH-1:0] input_axis_tdest = 0; -reg [USER_WIDTH-1:0] input_axis_tuser = 0; +reg [DATA_WIDTH-1:0] s_axis_tdata = 0; +reg [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 output_0_axis_tready = 0; -reg output_1_axis_tready = 0; -reg output_2_axis_tready = 0; -reg output_3_axis_tready = 0; +reg [M_COUNT-1:0] m_axis_tready = 0; reg enable = 0; -reg [1:0] select = 0; +reg drop = 0; +reg [$clog2(M_COUNT)-1:0] select = 0; // Outputs -wire input_axis_tready; +wire s_axis_tready; -wire [DATA_WIDTH-1:0] output_0_axis_tdata; -wire [KEEP_WIDTH-1:0] output_0_axis_tkeep; -wire output_0_axis_tvalid; -wire output_0_axis_tlast; -wire [ID_WIDTH-1:0] output_0_axis_tid; -wire [DEST_WIDTH-1:0] output_0_axis_tdest; -wire [USER_WIDTH-1:0] output_0_axis_tuser; -wire [DATA_WIDTH-1:0] output_1_axis_tdata; -wire [KEEP_WIDTH-1:0] output_1_axis_tkeep; -wire output_1_axis_tvalid; -wire output_1_axis_tlast; -wire [ID_WIDTH-1:0] output_1_axis_tid; -wire [DEST_WIDTH-1:0] output_1_axis_tdest; -wire [USER_WIDTH-1:0] output_1_axis_tuser; -wire [DATA_WIDTH-1:0] output_2_axis_tdata; -wire [KEEP_WIDTH-1:0] output_2_axis_tkeep; -wire output_2_axis_tvalid; -wire output_2_axis_tlast; -wire [ID_WIDTH-1:0] output_2_axis_tid; -wire [DEST_WIDTH-1:0] output_2_axis_tdest; -wire [USER_WIDTH-1:0] output_2_axis_tuser; -wire [DATA_WIDTH-1:0] output_3_axis_tdata; -wire [KEEP_WIDTH-1:0] output_3_axis_tkeep; -wire output_3_axis_tvalid; -wire output_3_axis_tlast; -wire [ID_WIDTH-1:0] output_3_axis_tid; -wire [DEST_WIDTH-1:0] output_3_axis_tdest; -wire [USER_WIDTH-1:0] output_3_axis_tuser; +wire [M_COUNT*DATA_WIDTH-1:0] m_axis_tdata; +wire [M_COUNT*KEEP_WIDTH-1:0] m_axis_tkeep; +wire [M_COUNT-1:0] m_axis_tvalid; +wire [M_COUNT-1:0] m_axis_tlast; +wire [M_COUNT*ID_WIDTH-1:0] m_axis_tid; +wire [M_COUNT*DEST_WIDTH-1:0] m_axis_tdest; +wire [M_COUNT*USER_WIDTH-1:0] m_axis_tuser; initial begin // myhdl integration @@ -101,50 +79,27 @@ initial begin clk, rst, current_test, - input_axis_tdata, - input_axis_tkeep, - input_axis_tvalid, - input_axis_tlast, - input_axis_tid, - input_axis_tdest, - input_axis_tuser, - output_0_axis_tready, - output_1_axis_tready, - output_2_axis_tready, - output_3_axis_tready, + s_axis_tdata, + s_axis_tkeep, + s_axis_tvalid, + s_axis_tlast, + s_axis_tid, + s_axis_tdest, + s_axis_tuser, + m_axis_tready, enable, + drop, select ); $to_myhdl( - input_axis_tready, - output_0_axis_tdata, - output_0_axis_tkeep, - output_0_axis_tvalid, - output_0_axis_tlast, - output_0_axis_tid, - output_0_axis_tdest, - output_0_axis_tuser, - output_1_axis_tdata, - output_1_axis_tkeep, - output_1_axis_tvalid, - output_1_axis_tlast, - output_1_axis_tid, - output_1_axis_tdest, - output_1_axis_tuser, - output_2_axis_tdata, - output_2_axis_tkeep, - output_2_axis_tvalid, - output_2_axis_tlast, - output_2_axis_tid, - output_2_axis_tdest, - output_2_axis_tuser, - output_3_axis_tdata, - output_3_axis_tkeep, - output_3_axis_tvalid, - output_3_axis_tlast, - output_3_axis_tid, - output_3_axis_tdest, - output_3_axis_tuser + 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 @@ -152,7 +107,8 @@ initial begin $dumpvars(0, test_axis_demux_4_64); end -axis_demux_4 #( +axis_demux #( + .M_COUNT(M_COUNT), .DATA_WIDTH(DATA_WIDTH), .KEEP_ENABLE(KEEP_ENABLE), .KEEP_WIDTH(KEEP_WIDTH), @@ -167,49 +123,26 @@ UUT ( .clk(clk), .rst(rst), // AXI input - .input_axis_tdata(input_axis_tdata), - .input_axis_tkeep(input_axis_tkeep), - .input_axis_tvalid(input_axis_tvalid), - .input_axis_tready(input_axis_tready), - .input_axis_tlast(input_axis_tlast), - .input_axis_tid(input_axis_tid), - .input_axis_tdest(input_axis_tdest), - .input_axis_tuser(input_axis_tuser), + .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 outputs - .output_0_axis_tdata(output_0_axis_tdata), - .output_0_axis_tkeep(output_0_axis_tkeep), - .output_0_axis_tvalid(output_0_axis_tvalid), - .output_0_axis_tready(output_0_axis_tready), - .output_0_axis_tlast(output_0_axis_tlast), - .output_0_axis_tid(output_0_axis_tid), - .output_0_axis_tdest(output_0_axis_tdest), - .output_0_axis_tuser(output_0_axis_tuser), - .output_1_axis_tdata(output_1_axis_tdata), - .output_1_axis_tkeep(output_1_axis_tkeep), - .output_1_axis_tvalid(output_1_axis_tvalid), - .output_1_axis_tready(output_1_axis_tready), - .output_1_axis_tlast(output_1_axis_tlast), - .output_1_axis_tid(output_1_axis_tid), - .output_1_axis_tdest(output_1_axis_tdest), - .output_1_axis_tuser(output_1_axis_tuser), - .output_2_axis_tdata(output_2_axis_tdata), - .output_2_axis_tkeep(output_2_axis_tkeep), - .output_2_axis_tvalid(output_2_axis_tvalid), - .output_2_axis_tready(output_2_axis_tready), - .output_2_axis_tlast(output_2_axis_tlast), - .output_2_axis_tid(output_2_axis_tid), - .output_2_axis_tdest(output_2_axis_tdest), - .output_2_axis_tuser(output_2_axis_tuser), - .output_3_axis_tdata(output_3_axis_tdata), - .output_3_axis_tkeep(output_3_axis_tkeep), - .output_3_axis_tvalid(output_3_axis_tvalid), - .output_3_axis_tready(output_3_axis_tready), - .output_3_axis_tlast(output_3_axis_tlast), - .output_3_axis_tid(output_3_axis_tid), - .output_3_axis_tdest(output_3_axis_tdest), - .output_3_axis_tuser(output_3_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), // Control .enable(enable), + .drop(drop), .select(select) );