/*
    Wishbone B-4 Crossbar
    *** Autogenerated file ***
*/

`default_nettype none
`include "Utils.vh"

module Crossbar5_wb #(
    parameter DATA_WIDTH = 32,
    parameter ADDR_WIDTH = 32,
    parameter SELECT_WIDTH = (DATA_WIDTH/8),
    parameter DEVICE0_ADDR = 32'h00000000,
    parameter DEVICE0_MASK = 32'h0000ff00,
    parameter DEVICE1_ADDR = 32'h00000000,
    parameter DEVICE1_MASK = 32'h0000ff00,
    parameter DEVICE2_ADDR = 32'h00000000,
    parameter DEVICE2_MASK = 32'h0000ff00,
    parameter DEVICE3_ADDR = 32'h00000000,
    parameter DEVICE3_MASK = 32'h0000ff00,
    parameter DEVICE4_ADDR = 32'h00000000,
    parameter DEVICE4_MASK = 32'h0000ff00
)(
    // Wishbone slave port
    input  wire [ADDR_WIDTH-1:0]   wbs_adr_i,
    input  wire [DATA_WIDTH-1:0]   wbs_dat_i,
    output reg  [DATA_WIDTH-1:0]   wbs_dat_o,
    input  wire                    wbs_we_i,
    input  wire [SELECT_WIDTH-1:0] wbs_sel_i,
    input  wire                    wbs_stb_i,
    input  wire                    wbs_cyc_i,
    output wire                    wbs_ack_o,
    output wire                    wbs_err_o,
    
    // Wishbone master 0 port
    output wire [ADDR_WIDTH-1:0]   wbm0_adr_o,
    input  wire [DATA_WIDTH-1:0]   wbm0_dat_i,
    output wire [DATA_WIDTH-1:0]   wbm0_dat_o,
    output wire                    wbm0_we_o,
    output wire [SELECT_WIDTH-1:0] wbm0_sel_o,
    output reg                     wbm0_cyc_o,
    output wire                    wbm0_stb_o,
    input  wire                    wbm0_ack_i,
    input  wire                    wbm0_err_i,
    
    // Wishbone master 1 port
    output wire [ADDR_WIDTH-1:0]   wbm1_adr_o,
    input  wire [DATA_WIDTH-1:0]   wbm1_dat_i,
    output wire [DATA_WIDTH-1:0]   wbm1_dat_o,
    output wire                    wbm1_we_o,
    output wire [SELECT_WIDTH-1:0] wbm1_sel_o,
    output reg                     wbm1_cyc_o,
    output wire                    wbm1_stb_o,
    input  wire                    wbm1_ack_i,
    input  wire                    wbm1_err_i,
    
    // Wishbone master 2 port
    output wire [ADDR_WIDTH-1:0]   wbm2_adr_o,
    input  wire [DATA_WIDTH-1:0]   wbm2_dat_i,
    output wire [DATA_WIDTH-1:0]   wbm2_dat_o,
    output wire                    wbm2_we_o,
    output wire [SELECT_WIDTH-1:0] wbm2_sel_o,
    output reg                     wbm2_cyc_o,
    output wire                    wbm2_stb_o,
    input  wire                    wbm2_ack_i,
    input  wire                    wbm2_err_i,
    
    // Wishbone master 3 port
    output wire [ADDR_WIDTH-1:0]   wbm3_adr_o,
    input  wire [DATA_WIDTH-1:0]   wbm3_dat_i,
    output wire [DATA_WIDTH-1:0]   wbm3_dat_o,
    output wire                    wbm3_we_o,
    output wire [SELECT_WIDTH-1:0] wbm3_sel_o,
    output reg                     wbm3_cyc_o,
    output wire                    wbm3_stb_o,
    input  wire                    wbm3_ack_i,
    input  wire                    wbm3_err_i,
    
    // Wishbone master 4 port
    output wire [ADDR_WIDTH-1:0]   wbm4_adr_o,
    input  wire [DATA_WIDTH-1:0]   wbm4_dat_i,
    output wire [DATA_WIDTH-1:0]   wbm4_dat_o,
    output wire                    wbm4_we_o,
    output wire [SELECT_WIDTH-1:0] wbm4_sel_o,
    output reg                     wbm4_cyc_o,
    output wire                    wbm4_stb_o,
    input  wire                    wbm4_ack_i,
    input  wire                    wbm4_err_i
);
    // Device selection
    localparam DEVICE_NONE = 'd0;
    localparam DEVICE_0 = 'd1;
    localparam DEVICE_1 = 'd2;
    localparam DEVICE_2 = 'd3;
    localparam DEVICE_3 = 'd4;
    localparam DEVICE_4 = 'd5;

    reg [2:0] selected_device;
    always @(*) begin
        selected_device = DEVICE_NONE;
        if (wbs_cyc_i) begin
            if ((wbs_adr_i & DEVICE0_MASK) == DEVICE0_ADDR)
                selected_device = DEVICE_0;
            if ((wbs_adr_i & DEVICE1_MASK) == DEVICE1_ADDR)
                selected_device = DEVICE_1;
            if ((wbs_adr_i & DEVICE2_MASK) == DEVICE2_ADDR)
                selected_device = DEVICE_2;
            if ((wbs_adr_i & DEVICE3_MASK) == DEVICE3_ADDR)
                selected_device = DEVICE_3;
            if ((wbs_adr_i & DEVICE4_MASK) == DEVICE4_ADDR)
                selected_device = DEVICE_4;
        end
    end

    // Master Addr Out
    assign wbm0_adr_o = wbs_adr_i;
    assign wbm1_adr_o = wbs_adr_i;
    assign wbm2_adr_o = wbs_adr_i;
    assign wbm3_adr_o = wbs_adr_i;
    assign wbm4_adr_o = wbs_adr_i;

    // Master Data in (Muxed)
    always @(*) begin /* COMBINATORIAL */
        case(selected_device)
            DEVICE_0:    wbs_dat_o = wbm0_dat_i;
            DEVICE_1:    wbs_dat_o = wbm1_dat_i;
            DEVICE_2:    wbs_dat_o = wbm2_dat_i;
            DEVICE_3:    wbs_dat_o = wbm3_dat_i;
            DEVICE_4:    wbs_dat_o = wbm4_dat_i;
            default: begin
                wbs_dat_o = 32'hxxxxxxxx;
            end
        endcase
    end
    
    // Master Data Out
    assign wbm0_dat_o = wbs_dat_i;
    assign wbm1_dat_o = wbs_dat_i;
    assign wbm2_dat_o = wbs_dat_i;
    assign wbm3_dat_o = wbs_dat_i;
    assign wbm4_dat_o = wbs_dat_i;
                 
    // Master WE Out
    assign wbm0_we_o = wbs_we_i;
    assign wbm1_we_o = wbs_we_i;
    assign wbm2_we_o = wbs_we_i;
    assign wbm3_we_o = wbs_we_i;
    assign wbm4_we_o = wbs_we_i;
    
    // Master Sel Out
    assign wbm0_sel_o = wbs_sel_i;
    assign wbm1_sel_o = wbs_sel_i;
    assign wbm2_sel_o = wbs_sel_i;
    assign wbm3_sel_o = wbs_sel_i;
    assign wbm4_sel_o = wbs_sel_i;
                 
    
    /*
        === Cyc muxing ===
    */
    always @(*) begin /* COMBINATORIAL */
        // Defaults
        wbm0_cyc_o = 1'b0;
        wbm1_cyc_o = 1'b0;
        wbm2_cyc_o = 1'b0;
        wbm3_cyc_o = 1'b0;
        wbm4_cyc_o = 1'b0;
        
        case(selected_device)
            DEVICE_0: wbm0_cyc_o = wbs_cyc_i;
            DEVICE_1: wbm1_cyc_o = wbs_cyc_i;
            DEVICE_2: wbm2_cyc_o = wbs_cyc_i;
            DEVICE_3: wbm3_cyc_o = wbs_cyc_i;
            DEVICE_4: wbm4_cyc_o = wbs_cyc_i;
            
            default: begin
                wbm0_cyc_o = 1'b0;
                wbm1_cyc_o = 1'b0;
                wbm2_cyc_o = 1'b0;
                wbm3_cyc_o = 1'b0;
                wbm4_cyc_o = 1'b0;
            end
        endcase
    end

    // Stb Out
    assign wbm0_stb_o = wbm0_cyc_o & wbs_stb_i;
    assign wbm1_stb_o = wbm1_cyc_o & wbs_stb_i;
    assign wbm2_stb_o = wbm2_cyc_o & wbs_stb_i;
    assign wbm3_stb_o = wbm3_cyc_o & wbs_stb_i;
    assign wbm4_stb_o = wbm4_cyc_o & wbs_stb_i;
                 
    // ACK Out
    assign wbs_ack_o = wbm0_ack_i 
                        | wbm1_ack_i 
                        | wbm2_ack_i 
                        | wbm3_ack_i 
                        | wbm4_ack_i;
                 
    // Error signal
    wire select_error = (selected_device == DEVICE_NONE);
    always @(*) begin
        if (select_error) begin 
            `debug($display("XBAR-SEL-ERR: Unknown Device Selected: 0x%x", wbs_adr_i);) 
        end
    end
    
    assign wbs_err_o = wbs_cyc_i & (select_error
                        | wbm0_err_i
                        | wbm1_err_i
                        | wbm2_err_i
                        | wbm3_err_i
                        | wbm4_err_i);
endmodule
