`include "VX_cache_config.vh"

module VX_cache #(
    parameter CACHE_ID                      = 0,
    // Size of cache in bytes
    parameter CACHE_SIZE                    = 2048, 
    // Size of line inside a bank in bytes
    parameter BANK_LINE_SIZE                = 16, 
    // Number of banks {1, 2, 4, 8,...}
    parameter NUM_BANKS                     = 8, 
    // Size of a word in bytes
    parameter WORD_SIZE                     = 4, 
    // Number of Word requests per cycle {1, 2, 4, 8, ...}
    parameter NUM_REQUESTS                  = 4, 

    // Queues feeding into banks Knobs {1, 2, 4, 8, ...}

    // Core Request Queue Size
    parameter CREQ_SIZE                     = 8, 
    // Miss Reserv Queue Knob
    parameter MRVQ_SIZE                     = 16, 
    // Dram Fill Rsp Queue Size
    parameter DFPQ_SIZE                     = 16, 
    // Snoop Req Queue Size
    parameter SNRQ_SIZE                     = 16, 

    // Queues for writebacks Knobs {1, 2, 4, 8, ...}
    // Core Writeback Queue Size
    parameter CWBQ_SIZE                     = 8, 
    // Dram Writeback Queue Size
    parameter DWBQ_SIZE                     = 4, 
    // Dram Fill Req Queue Size
    parameter DFQQ_SIZE                     = 8, 

    // Enable cache writeable
    parameter WRITE_ENABLE                  = 1,

    // Enable dram update
    parameter DRAM_ENABLE                   = 1,

    // Enable snoop forwarding
    parameter SNOOP_FORWARDING              = 0,

    // core request tag size
    parameter CORE_TAG_WIDTH                = 42,

    // size of tag id in core request tag
    parameter CORE_TAG_ID_BITS              = 8,

    // dram request tag size
    parameter DRAM_TAG_WIDTH                = 28,

    // Number of snoop forwarding requests
    parameter NUM_SNP_REQUESTS              = 1, 

    // Snooping request tag width
    parameter SNP_REQ_TAG_WIDTH             = 1,

    // Snooping forward tag width
    parameter SNP_FWD_TAG_WIDTH             = 1
 ) (
    `SCOPE_IO_VX_cache
    
    input wire clk,
    input wire reset,

    // Core request    
    input wire [NUM_REQUESTS-1:0]                           core_req_valid,
    input wire [`CORE_REQ_TAG_COUNT-1:0]                    core_req_rw,
    input wire [NUM_REQUESTS-1:0][WORD_SIZE-1:0]            core_req_byteen,
    input wire [NUM_REQUESTS-1:0][`WORD_ADDR_WIDTH-1:0]     core_req_addr,
    input wire [NUM_REQUESTS-1:0][`WORD_WIDTH-1:0]          core_req_data,
    input wire [`CORE_REQ_TAG_COUNT-1:0][CORE_TAG_WIDTH-1:0] core_req_tag,
    output wire                                             core_req_ready,

    // Core response
    output wire [NUM_REQUESTS-1:0]                          core_rsp_valid,    
    output wire [NUM_REQUESTS-1:0][`WORD_WIDTH-1:0]         core_rsp_data,
    output wire [`CORE_REQ_TAG_COUNT-1:0][CORE_TAG_WIDTH-1:0] core_rsp_tag,
    input  wire                                             core_rsp_ready,   
    
    // DRAM request
    output wire                             dram_req_valid,
    output wire                             dram_req_rw,    
    output wire [BANK_LINE_SIZE-1:0]        dram_req_byteen,    
    output wire [`DRAM_ADDR_WIDTH-1:0]      dram_req_addr,
    output wire [`BANK_LINE_WIDTH-1:0]      dram_req_data,
    output wire [DRAM_TAG_WIDTH-1:0]        dram_req_tag,
    input  wire                             dram_req_ready,
    
    // DRAM response
    input  wire                             dram_rsp_valid,    
    input  wire [`BANK_LINE_WIDTH-1:0]      dram_rsp_data,
    input  wire [DRAM_TAG_WIDTH-1:0]        dram_rsp_tag,
    output wire                             dram_rsp_ready,    

    // Snoop request
    input wire                              snp_req_valid,
    input wire [`DRAM_ADDR_WIDTH-1:0]       snp_req_addr,
    input wire                              snp_req_invalidate,
    input wire [SNP_REQ_TAG_WIDTH-1:0]      snp_req_tag,
    output wire                             snp_req_ready,

    // Snoop response
    output wire                             snp_rsp_valid,    
    output wire [SNP_REQ_TAG_WIDTH-1:0]     snp_rsp_tag,
    input  wire                             snp_rsp_ready,

    // Snoop Forwarding out
    output wire [NUM_SNP_REQUESTS-1:0]      snp_fwdout_valid,
    output wire [NUM_SNP_REQUESTS-1:0][`DRAM_ADDR_WIDTH-1:0] snp_fwdout_addr,
    output wire [NUM_SNP_REQUESTS-1:0]      snp_fwdout_invalidate,
    output wire [NUM_SNP_REQUESTS-1:0][SNP_FWD_TAG_WIDTH-1:0] snp_fwdout_tag,
`IGNORE_WARNINGS_BEGIN
    input wire [NUM_SNP_REQUESTS-1:0]       snp_fwdout_ready,

    // Snoop forwarding in
    input wire [NUM_SNP_REQUESTS-1:0]       snp_fwdin_valid,    
    input wire [NUM_SNP_REQUESTS-1:0][SNP_FWD_TAG_WIDTH-1:0] snp_fwdin_tag,
`IGNORE_WARNINGS_END
    output wire [NUM_SNP_REQUESTS-1:0]      snp_fwdin_ready
);

`ifdef DBG_CORE_REQ_INFO
    /* verilator lint_off UNUSED */
    wire[31:0]           debug_core_req_use_pc;
    wire[`NR_BITS-1:0]   debug_core_req_rd;
    wire[`NW_BITS-1:0]   debug_core_req_wid;
    wire[`UP(CORE_TAG_ID_BITS)-1:0] debug_core_req_idx;
    /* verilator lint_on UNUSED */

    if (WORD_SIZE != `GLOBAL_BLOCK_SIZE) begin
        assign {debug_core_req_use_pc, debug_core_req_rd, debug_core_req_wid, debug_core_req_idx} = core_req_tag[0];
    end
`endif

    wire [NUM_BANKS-1:0][NUM_REQUESTS-1:0]      per_bank_valid;

    wire [NUM_BANKS-1:0]                        per_bank_core_req_ready;
    
    wire [NUM_BANKS-1:0]                        per_bank_core_rsp_valid;
    wire [NUM_BANKS-1:0][`REQS_BITS-1:0]        per_bank_core_rsp_tid; 
    wire [NUM_BANKS-1:0][`WORD_WIDTH-1:0]       per_bank_core_rsp_data;
    wire [NUM_BANKS-1:0][CORE_TAG_WIDTH-1:0]    per_bank_core_rsp_tag;    
    wire [NUM_BANKS-1:0]                        per_bank_core_rsp_ready;

    wire [NUM_BANKS-1:0]                        per_bank_dram_fill_req_valid;
    wire [NUM_BANKS-1:0][`DRAM_ADDR_WIDTH-1:0]  per_bank_dram_fill_req_addr;
    wire                                        dram_fill_req_ready;

    wire [NUM_BANKS-1:0]                        per_bank_dram_fill_rsp_ready;

    wire [NUM_BANKS-1:0]                        per_bank_dram_wb_req_ready;
    wire [NUM_BANKS-1:0]                        per_bank_dram_wb_req_valid;    
    wire [NUM_BANKS-1:0][BANK_LINE_SIZE-1:0]    per_bank_dram_wb_req_byteen;    
    wire [NUM_BANKS-1:0][`DRAM_ADDR_WIDTH-1:0]  per_bank_dram_wb_req_addr;
    wire [NUM_BANKS-1:0][`BANK_LINE_WIDTH-1:0]  per_bank_dram_wb_req_data;

    wire [NUM_BANKS-1:0]                        per_bank_snp_req_ready;

    wire [NUM_BANKS-1:0]                        per_bank_snp_rsp_valid;
    wire [NUM_BANKS-1:0][SNP_REQ_TAG_WIDTH-1:0] per_bank_snp_rsp_tag;
    wire [NUM_BANKS-1:0]                        per_bank_snp_rsp_ready;

    wire                         snp_req_valid_qual;    
    wire [`DRAM_ADDR_WIDTH-1:0]  snp_req_addr_qual;
    wire                         snp_req_invalidate_qual;    
    wire [SNP_REQ_TAG_WIDTH-1:0] snp_req_tag_qual;
    wire                         snp_req_ready_qual;

    if (SNOOP_FORWARDING) begin
        VX_snp_forwarder #(
            .CACHE_ID          (CACHE_ID),
            .BANK_LINE_SIZE    (BANK_LINE_SIZE), 
            .NUM_REQUESTS      (NUM_SNP_REQUESTS), 
            .SNRQ_SIZE         (SNRQ_SIZE),
            .SNP_REQ_TAG_WIDTH (SNP_REQ_TAG_WIDTH)
        ) snp_forwarder (
            .clk                (clk),
            .reset              (reset),

            .snp_req_valid      (snp_req_valid),
            .snp_req_addr       (snp_req_addr),
            .snp_req_invalidate (snp_req_invalidate),
            .snp_req_tag        (snp_req_tag),
            .snp_req_ready      (snp_req_ready),

            .snp_rsp_valid      (snp_req_valid_qual),
            .snp_rsp_addr       (snp_req_addr_qual),
            .snp_rsp_invalidate (snp_req_invalidate_qual),
            .snp_rsp_tag        (snp_req_tag_qual),
            .snp_rsp_ready      (snp_req_ready_qual),   

            .snp_fwdout_valid   (snp_fwdout_valid),
            .snp_fwdout_addr    (snp_fwdout_addr),
            .snp_fwdout_invalidate(snp_fwdout_invalidate),
            .snp_fwdout_tag     (snp_fwdout_tag),
            .snp_fwdout_ready   (snp_fwdout_ready),

            .snp_fwdin_valid    (snp_fwdin_valid),
            .snp_fwdin_tag      (snp_fwdin_tag),
            .snp_fwdin_ready    (snp_fwdin_ready)      
        );
    end else begin
        assign snp_fwdout_valid = 0;
        assign snp_fwdout_addr  = 0;
        assign snp_fwdout_invalidate = 0;
        assign snp_fwdout_tag   = 0;

        assign snp_fwdin_ready  = 0;

        assign snp_req_valid_qual      = snp_req_valid;
        assign snp_req_addr_qual       = snp_req_addr;
        assign snp_req_invalidate_qual = snp_req_invalidate;
        assign snp_req_tag_qual        = snp_req_tag;
        assign snp_req_ready           = snp_req_ready_qual;
    end    

    if (NUM_BANKS == 1) begin
        assign snp_req_ready_qual = per_bank_snp_req_ready;
    end else begin
        assign snp_req_ready_qual = per_bank_snp_req_ready[`DRAM_ADDR_BANK(snp_req_addr_qual)];
    end    

    VX_cache_core_req_bank_sel #(
        .BANK_LINE_SIZE (BANK_LINE_SIZE),
        .NUM_BANKS      (NUM_BANKS),
        .WORD_SIZE      (WORD_SIZE),
        .NUM_REQUESTS   (NUM_REQUESTS)
    ) cache_core_req_bank_sel (
        .core_req_valid  (core_req_valid),
        .per_bank_ready  (per_bank_core_req_ready),
        .core_req_addr   (core_req_addr),
        .per_bank_valid  (per_bank_valid),
        .core_req_ready  (core_req_ready)
    );

    assign dram_req_tag   = dram_req_addr;
    assign dram_rsp_ready = (| per_bank_dram_fill_rsp_ready);
    
    for (genvar i = 0; i < NUM_BANKS; i++) begin
        wire [NUM_REQUESTS-1:0]                             curr_bank_core_req_valid;            
        wire [`CORE_REQ_TAG_COUNT-1:0]                      curr_bank_core_req_rw;  
        wire [NUM_REQUESTS-1:0][WORD_SIZE-1:0]              curr_bank_core_req_byteen;
        wire [NUM_REQUESTS-1:0][`WORD_ADDR_WIDTH-1:0]       curr_bank_core_req_addr;
        wire [`CORE_REQ_TAG_COUNT-1:0][CORE_TAG_WIDTH-1:0]  curr_bank_core_req_tag;
        wire [NUM_REQUESTS-1:0][`WORD_WIDTH-1:0]            curr_bank_core_req_data;

        wire                            curr_bank_core_rsp_valid;
        wire [`REQS_BITS-1:0]           curr_bank_core_rsp_tid;
        wire [`WORD_WIDTH-1:0]          curr_bank_core_rsp_data;
        wire [CORE_TAG_WIDTH-1:0]       curr_bank_core_rsp_tag;
        wire                            curr_bank_core_rsp_ready;

        wire                            curr_bank_dram_fill_rsp_valid;            
        wire [`BANK_LINE_WIDTH-1:0]     curr_bank_dram_fill_rsp_data;
        wire [`LINE_ADDR_WIDTH-1:0]     curr_bank_dram_fill_rsp_addr;
        wire                            curr_bank_dram_fill_rsp_ready;

        wire                            curr_bank_dram_fill_req_valid;            
        wire [`LINE_ADDR_WIDTH-1:0]     curr_bank_dram_fill_req_addr;
        wire                            curr_bank_dram_fill_req_ready;

        wire                            curr_bank_dram_wb_req_valid;
        wire [BANK_LINE_SIZE-1:0]       curr_bank_dram_wb_req_byteen;
        wire [`LINE_ADDR_WIDTH-1:0]     curr_bank_dram_wb_req_addr;
        wire[`BANK_LINE_WIDTH-1:0]      curr_bank_dram_wb_req_data;
        wire                            curr_bank_dram_wb_req_ready;

        wire                            curr_bank_snp_req_valid;
        wire [`LINE_ADDR_WIDTH-1:0]     curr_bank_snp_req_addr;
        wire                            curr_bank_snp_req_invalidate;
        wire [SNP_REQ_TAG_WIDTH-1:0]    curr_bank_snp_req_tag;
        wire                            curr_bank_snp_req_ready;    

        wire                            curr_bank_snp_rsp_valid;
        wire [SNP_REQ_TAG_WIDTH-1:0]    curr_bank_snp_rsp_tag;
        wire                            curr_bank_snp_rsp_ready;                    

        wire                            curr_bank_core_req_ready;

        // Core Req
        assign curr_bank_core_req_valid   = (per_bank_valid[i] & {NUM_REQUESTS{core_req_ready}});
        assign curr_bank_core_req_addr    = core_req_addr;
        assign curr_bank_core_req_rw      = core_req_rw;
        assign curr_bank_core_req_byteen  = core_req_byteen;
        assign curr_bank_core_req_data    = core_req_data;
        assign curr_bank_core_req_tag     = core_req_tag;
        assign per_bank_core_req_ready[i] = curr_bank_core_req_ready;

        // Core WB
        assign curr_bank_core_rsp_ready    = per_bank_core_rsp_ready[i];
        assign per_bank_core_rsp_valid [i] = curr_bank_core_rsp_valid;
        assign per_bank_core_rsp_tid   [i] = curr_bank_core_rsp_tid;
        assign per_bank_core_rsp_tag   [i] = curr_bank_core_rsp_tag;
        assign per_bank_core_rsp_data  [i] = curr_bank_core_rsp_data;

        // Dram fill request            
        assign per_bank_dram_fill_req_valid[i] = curr_bank_dram_fill_req_valid;
        if (NUM_BANKS == 1) begin
            assign per_bank_dram_fill_req_addr[i] = curr_bank_dram_fill_req_addr;
        end else begin
            assign per_bank_dram_fill_req_addr[i] = `LINE_TO_DRAM_ADDR(curr_bank_dram_fill_req_addr, i);
        end
        assign curr_bank_dram_fill_req_ready = dram_fill_req_ready;

        // Dram fill response
        if (NUM_BANKS == 1) begin
            assign curr_bank_dram_fill_rsp_valid = dram_rsp_valid;
            assign curr_bank_dram_fill_rsp_addr  = dram_rsp_tag;
        end else begin
            assign curr_bank_dram_fill_rsp_valid = dram_rsp_valid && (`DRAM_ADDR_BANK(dram_rsp_tag) == i);
            assign curr_bank_dram_fill_rsp_addr  = `DRAM_TO_LINE_ADDR(dram_rsp_tag);    
        end
        assign curr_bank_dram_fill_rsp_data    = dram_rsp_data;
        assign per_bank_dram_fill_rsp_ready[i] = curr_bank_dram_fill_rsp_ready;

        // Dram writeback request            
        assign per_bank_dram_wb_req_valid[i] = curr_bank_dram_wb_req_valid;          
        assign per_bank_dram_wb_req_byteen[i] = curr_bank_dram_wb_req_byteen;
        if (NUM_BANKS == 1) begin  
            assign per_bank_dram_wb_req_addr[i] = curr_bank_dram_wb_req_addr;
        end else begin
            assign per_bank_dram_wb_req_addr[i] = `LINE_TO_DRAM_ADDR(curr_bank_dram_wb_req_addr, i);            
        end
        assign per_bank_dram_wb_req_data[i] = curr_bank_dram_wb_req_data;
        assign curr_bank_dram_wb_req_ready  = per_bank_dram_wb_req_ready[i];

        // Snoop request
        if (NUM_BANKS == 1) begin
            assign curr_bank_snp_req_valid = snp_req_valid_qual;
            assign curr_bank_snp_req_addr  = snp_req_addr_qual;
        end else begin
            assign curr_bank_snp_req_valid = snp_req_valid_qual && (`DRAM_ADDR_BANK(snp_req_addr_qual) == i);
            assign curr_bank_snp_req_addr  = `DRAM_TO_LINE_ADDR(snp_req_addr_qual);
        end
        assign curr_bank_snp_req_invalidate = snp_req_invalidate_qual;
        assign curr_bank_snp_req_tag        = snp_req_tag_qual;
        assign per_bank_snp_req_ready[i]    = curr_bank_snp_req_ready;

        // Snoop response            
        assign per_bank_snp_rsp_valid[i] = curr_bank_snp_rsp_valid;
        assign per_bank_snp_rsp_tag[i]   = curr_bank_snp_rsp_tag;
        assign curr_bank_snp_rsp_ready   = per_bank_snp_rsp_ready[i];
        
        VX_bank #(                
            .BANK_ID            (i),
            .CACHE_ID           (CACHE_ID),
            .CACHE_SIZE         (CACHE_SIZE),
            .BANK_LINE_SIZE     (BANK_LINE_SIZE),
            .NUM_BANKS          (NUM_BANKS),
            .WORD_SIZE          (WORD_SIZE),
            .NUM_REQUESTS       (NUM_REQUESTS),
            .CREQ_SIZE          (CREQ_SIZE),
            .MRVQ_SIZE          (MRVQ_SIZE),
            .DFPQ_SIZE          (DFPQ_SIZE),
            .SNRQ_SIZE          (SNRQ_SIZE),
            .CWBQ_SIZE          (CWBQ_SIZE),
            .DWBQ_SIZE          (DWBQ_SIZE),
            .DFQQ_SIZE          (DFQQ_SIZE),
            .DRAM_ENABLE        (DRAM_ENABLE),
            .WRITE_ENABLE       (WRITE_ENABLE),
            .SNOOP_FORWARDING   (SNOOP_FORWARDING),
            .CORE_TAG_WIDTH     (CORE_TAG_WIDTH),                
            .CORE_TAG_ID_BITS   (CORE_TAG_ID_BITS),
            .SNP_REQ_TAG_WIDTH  (SNP_REQ_TAG_WIDTH)
        ) bank (
            `SCOPE_BIND_VX_cache_bank(i)
            
            .clk                     (clk),
            .reset                   (reset),                
            // Core request
            .core_req_valid          (curr_bank_core_req_valid),                  
            .core_req_rw             (curr_bank_core_req_rw),
            .core_req_byteen         (curr_bank_core_req_byteen),              
            .core_req_addr           (curr_bank_core_req_addr),
            .core_req_data           (curr_bank_core_req_data),
            .core_req_tag            (curr_bank_core_req_tag),
            .core_req_ready          (curr_bank_core_req_ready),

            // Core response                
            .core_rsp_valid          (curr_bank_core_rsp_valid),
            .core_rsp_tid            (curr_bank_core_rsp_tid),
            .core_rsp_data           (curr_bank_core_rsp_data),
            .core_rsp_tag            (curr_bank_core_rsp_tag),
            .core_rsp_ready          (curr_bank_core_rsp_ready),

            // Dram fill request
            .dram_fill_req_valid     (curr_bank_dram_fill_req_valid),
            .dram_fill_req_addr      (curr_bank_dram_fill_req_addr),
            .dram_fill_req_ready     (curr_bank_dram_fill_req_ready),

            // Dram fill response
            .dram_fill_rsp_valid     (curr_bank_dram_fill_rsp_valid),                
            .dram_fill_rsp_data      (curr_bank_dram_fill_rsp_data),
            .dram_fill_rsp_addr      (curr_bank_dram_fill_rsp_addr),
            .dram_fill_rsp_ready     (curr_bank_dram_fill_rsp_ready),

            // Dram writeback request               
            .dram_wb_req_valid       (curr_bank_dram_wb_req_valid),
            .dram_wb_req_byteen      (curr_bank_dram_wb_req_byteen),
            .dram_wb_req_addr        (curr_bank_dram_wb_req_addr),
            .dram_wb_req_data        (curr_bank_dram_wb_req_data),   
            .dram_wb_req_ready       (curr_bank_dram_wb_req_ready),

            // Snoop request
            .snp_req_valid           (curr_bank_snp_req_valid),
            .snp_req_addr            (curr_bank_snp_req_addr),
            .snp_req_invalidate      (curr_bank_snp_req_invalidate),
            .snp_req_tag             (curr_bank_snp_req_tag),
            .snp_req_ready           (curr_bank_snp_req_ready),

            // Snoop response
            .snp_rsp_valid           (curr_bank_snp_rsp_valid),
            .snp_rsp_tag             (curr_bank_snp_rsp_tag),
            .snp_rsp_ready           (curr_bank_snp_rsp_ready)
        );
    end   

    VX_cache_dram_req_arb #(
        .BANK_LINE_SIZE (BANK_LINE_SIZE),
        .NUM_BANKS      (NUM_BANKS),
        .WORD_SIZE      (WORD_SIZE),
        .DFQQ_SIZE      (DFQQ_SIZE)
    ) cache_dram_req_arb (
        .clk                          (clk),
        .reset                        (reset),        
        .per_bank_dram_fill_req_valid (per_bank_dram_fill_req_valid),
        .per_bank_dram_fill_req_addr  (per_bank_dram_fill_req_addr),
        .dram_fill_req_ready          (dram_fill_req_ready),
        .per_bank_dram_wb_req_valid   (per_bank_dram_wb_req_valid),        
        .per_bank_dram_wb_req_byteen  (per_bank_dram_wb_req_byteen),
        .per_bank_dram_wb_req_addr    (per_bank_dram_wb_req_addr),
        .per_bank_dram_wb_req_data    (per_bank_dram_wb_req_data),
        .per_bank_dram_wb_req_ready   (per_bank_dram_wb_req_ready),
        .dram_req_valid               (dram_req_valid),
        .dram_req_rw                  (dram_req_rw),        
        .dram_req_byteen              (dram_req_byteen),        
        .dram_req_addr                (dram_req_addr),
        .dram_req_data                (dram_req_data),  
        .dram_req_ready               (dram_req_ready)
    );    

    VX_cache_core_rsp_merge #(
        .NUM_BANKS          (NUM_BANKS),
        .WORD_SIZE          (WORD_SIZE),
        .NUM_REQUESTS       (NUM_REQUESTS),
        .CORE_TAG_WIDTH     (CORE_TAG_WIDTH),        
        .CORE_TAG_ID_BITS   (CORE_TAG_ID_BITS)
    ) cache_core_rsp_merge (
        .clk                     (clk),
        .reset                   (reset),       
        .per_bank_core_rsp_tid   (per_bank_core_rsp_tid),                
        .per_bank_core_rsp_valid (per_bank_core_rsp_valid),   
        .per_bank_core_rsp_data  (per_bank_core_rsp_data),
        .per_bank_core_rsp_tag   (per_bank_core_rsp_tag),
        .per_bank_core_rsp_ready (per_bank_core_rsp_ready),
        .core_rsp_valid          (core_rsp_valid),
        .core_rsp_data           (core_rsp_data),        
        .core_rsp_tag            (core_rsp_tag),
        .core_rsp_ready          (core_rsp_ready)
    );  

    VX_snp_rsp_arb #(
        .NUM_BANKS         (NUM_BANKS),
        .BANK_LINE_SIZE    (BANK_LINE_SIZE),
        .SNP_REQ_TAG_WIDTH (SNP_REQ_TAG_WIDTH)
    ) snp_rsp_arb ( 
        .clk                    (clk),
        .reset                  (reset),
        .per_bank_snp_rsp_valid (per_bank_snp_rsp_valid),
        .per_bank_snp_rsp_tag   (per_bank_snp_rsp_tag),
        .per_bank_snp_rsp_ready (per_bank_snp_rsp_ready),
        .snp_rsp_valid          (snp_rsp_valid),
        .snp_rsp_tag            (snp_rsp_tag),
        .snp_rsp_ready          (snp_rsp_ready)
    );
    
endmodule
