// // Copyright 2012 Ettus Research LLC // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // `define LOG2(N) (\ N < 2 ? 0 : \ N < 4 ? 1 : \ N < 8 ? 2 : \ N < 16 ? 3 : \ N < 32 ? 4 : \ N < 64 ? 5 : \ N < 128 ? 6 : \ N < 256 ? 7 : \ N < 512 ? 8 : \ N < 1024 ? 9 : \ 10) module axi_crossbar #( parameter FIFO_WIDTH = 64, // AXI4-STREAM data bus width parameter DST_WIDTH = 16, // Width of DST field we are routing on. parameter NUM_INPUTS = 2, // number of input AXI4-STREAM buses parameter NUM_OUTPUTS = 2 // number of output AXI4-STREAM buses ) ( input clk, input reset, input clear, input [7:0] local_addr, // Inputs input [(FIFO_WIDTH*NUM_INPUTS)-1:0] i_tdata, input [NUM_INPUTS-1:0] i_tvalid, input [NUM_INPUTS-1:0] i_tlast, output [NUM_INPUTS-1:0] i_tready, input [NUM_INPUTS-1:0] pkt_present, // Setting Bus input set_stb, input [15:0] set_addr, input [31:0] set_data, // Output output [(FIFO_WIDTH*NUM_OUTPUTS)-1:0] o_tdata, output [NUM_OUTPUTS-1:0] o_tvalid, output [NUM_OUTPUTS-1:0] o_tlast, input [NUM_OUTPUTS-1:0] o_tready, // readback bus input rb_rd_stb, input [`LOG2(NUM_OUTPUTS)+`LOG2(NUM_INPUTS)-1:0] rb_addr, output [31:0] rb_data ); genvar m,n; wire [(NUM_INPUTS*NUM_OUTPUTS)-1:0] forward_valid_in; wire [(NUM_INPUTS*NUM_OUTPUTS)-1:0] forward_ack_in; wire [(NUM_INPUTS*NUM_OUTPUTS)-1:0] forward_valid_out; wire [(NUM_INPUTS*NUM_OUTPUTS)-1:0] forward_ack_out; wire [NUM_INPUTS-1:0] i_tready_slave [0:NUM_OUTPUTS-1]; // // Instantiate an axi_slave_mux for every slave/output of the Crossbar switch. // Each axi_slave_mux contains logic to maux and resolve arbitration // for this particular slave/output. // generate for (m = 0; m < NUM_OUTPUTS; m = m + 1) begin: instantiate_slave_mux wire [NUM_INPUTS-1:0] i_tready_tmp; axi_slave_mux #( .FIFO_WIDTH(FIFO_WIDTH), // AXI4-STREAM data bus width .DST_WIDTH(DST_WIDTH), // Width of DST field we are routing on. .NUM_INPUTS(NUM_INPUTS) // number of input AXI buses ) axi_slave_mux_i ( .clk(clk), .reset(reset), .clear(clear), // Inputs .i_tdata(i_tdata), .i_tvalid(i_tvalid), .i_tlast(i_tlast), .i_tready(i_tready_tmp), // Forwarding flags (One from each Input/Master) .forward_valid(forward_valid_in[(m+1)*NUM_INPUTS-1:m*NUM_INPUTS]), .forward_ack(forward_ack_out[(m+1)*NUM_INPUTS-1:m*NUM_INPUTS]), // Output .o_tdata(o_tdata[(m*FIFO_WIDTH)+FIFO_WIDTH-1:m*FIFO_WIDTH]), .o_tvalid(o_tvalid[m]), .o_tlast(o_tlast[m]), .o_tready(o_tready[m]) ); if (m==0) assign i_tready_slave[0] = i_tready_tmp; else assign i_tready_slave[m] = i_tready_tmp | i_tready_slave[m-1] ; end // block: instantiate_slave_mux endgenerate assign i_tready = i_tready_slave[NUM_OUTPUTS-1]; // // Permute the forwarding flag buses // generate for (m = 0; m < NUM_OUTPUTS; m = m + 1) begin: permute_outer for (n = 0; n < NUM_INPUTS; n = n + 1) begin: permute_inner assign forward_valid_in[n*NUM_OUTPUTS+m] = forward_valid_out[n+m*NUM_INPUTS]; assign forward_ack_in[n+m*NUM_INPUTS] = forward_ack_out[n*NUM_OUTPUTS+m]; end end endgenerate // // Instantiate an axi_forwarding_cam for every Input/Master of the Crossbar switch. // Each contains a TCAM like lookup that allocates an egress port. // wire [31:0] rb_data_mux[0:NUM_INPUTS-1]; generate for (m = 0; m < NUM_INPUTS; m = m + 1) begin: instantiate_cam axi_forwarding_cam #( .BASE(0), .WIDTH(FIFO_WIDTH), // Bit width of FIFO word. .NUM_OUTPUTS(NUM_OUTPUTS) ) axi_forwarding_cam_i ( .clk(clk), .reset(reset), .clear(clear), // Monitored FIFO signals .o_tdata(i_tdata[(m*FIFO_WIDTH)+FIFO_WIDTH-1:m*FIFO_WIDTH]), .o_tvalid(i_tvalid[m]), .o_tready(i_tready[m]), .o_tlast(i_tlast[m]), .pkt_present(pkt_present[m]), // Configuration .local_addr(local_addr), // Setting Bus .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data), // Header signals .forward_valid(forward_valid_out[(m+1)*NUM_OUTPUTS-1:m*NUM_OUTPUTS]), .forward_ack(forward_ack_in[(m+1)*NUM_OUTPUTS-1:m*NUM_OUTPUTS]), // Readback bus .rb_rd_stb(rb_rd_strobe && (rb_addr[`LOG2(NUM_OUTPUTS)+`LOG2(NUM_INPUTS)-1:`LOG2(NUM_OUTPUTS)] == m)), .rb_addr(rb_addr[`LOG2(NUM_OUTPUTS)-1:0]), .rb_data(rb_data_mux[m]) ); end // block: instantiate_fifo_header endgenerate assign rb_data = rb_data_mux[rb_addr[`LOG2(NUM_OUTPUTS)+`LOG2(NUM_INPUTS)-1:`LOG2(NUM_OUTPUTS)]]; endmodule // axi_crossbar