`include "VX_cache_config.vh" module VX_snp_forwarder #( parameter CACHE_ID = 0, parameter BANK_LINE_SIZE = 1, parameter NUM_REQUESTS = 1, parameter SNRQ_SIZE = 1, parameter SNP_REQ_TAG_WIDTH = 1, parameter SNP_FWD_TAG_WIDTH = 1 ) ( input wire clk, input wire reset, // 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 [`DRAM_ADDR_WIDTH-1:0] snp_rsp_addr, output wire snp_rsp_invalidate, output wire [SNP_REQ_TAG_WIDTH-1:0] snp_rsp_tag, input wire snp_rsp_ready, // Snoop Forwarding out output wire [NUM_REQUESTS-1:0] snp_fwdout_valid, output wire [NUM_REQUESTS-1:0][`DRAM_ADDR_WIDTH-1:0] snp_fwdout_addr, output wire [NUM_REQUESTS-1:0] snp_fwdout_invalidate, output wire [NUM_REQUESTS-1:0][`LOG2UP(SNRQ_SIZE)-1:0] snp_fwdout_tag, input wire [NUM_REQUESTS-1:0] snp_fwdout_ready, // Snoop forwarding in input wire [NUM_REQUESTS-1:0] snp_fwdin_valid, input wire [NUM_REQUESTS-1:0][`LOG2UP(SNRQ_SIZE)-1:0] snp_fwdin_tag, output wire [NUM_REQUESTS-1:0] snp_fwdin_ready ); `STATIC_ASSERT(NUM_REQUESTS > 1, ("invalid value")) reg [`REQS_BITS:0] pending_cntrs [SNRQ_SIZE-1:0]; wire [`LOG2UP(SNRQ_SIZE)-1:0] sfq_write_addr, sfq_read_addr; wire sfq_acquire, sfq_release, sfq_full; wire fwdin_valid; wire [`LOG2UP(SNRQ_SIZE)-1:0] fwdin_tag; wire fwdin_ready = snp_rsp_ready || (1 != pending_cntrs[sfq_read_addr]); wire fwdin_fire = fwdin_valid && fwdin_ready; wire fwdout_ready = (& snp_fwdout_ready); assign snp_rsp_valid = fwdin_valid && (1 == pending_cntrs[sfq_read_addr]); // send response assign sfq_read_addr = fwdin_tag; assign sfq_acquire = snp_req_valid && !sfq_full && fwdout_ready; assign sfq_release = snp_rsp_valid && snp_rsp_ready; VX_cam_buffer #( .DATAW (`DRAM_ADDR_WIDTH + 1 + SNP_REQ_TAG_WIDTH), .SIZE (SNRQ_SIZE) ) snp_fwd_cam ( .clk (clk), .reset (reset), .write_addr (sfq_write_addr), .acquire_slot (sfq_acquire), .read_addr (sfq_read_addr), .write_data ({snp_req_addr, snp_req_invalidate, snp_req_tag}), .read_data ({snp_rsp_addr, snp_rsp_invalidate, snp_rsp_tag}), .release_addr (sfq_read_addr), .release_slot (sfq_release), .full (sfq_full) ); always @(posedge clk) begin if (sfq_acquire) begin pending_cntrs[sfq_write_addr] <= NUM_REQUESTS; end if (fwdin_fire) begin pending_cntrs[sfq_read_addr] <= pending_cntrs[sfq_read_addr] - 1; end end for (genvar i = 0; i < NUM_REQUESTS; i++) begin assign snp_fwdout_valid[i] = snp_req_valid && snp_req_ready; assign snp_fwdout_addr[i] = snp_req_addr; assign snp_fwdout_invalidate[i] = snp_req_invalidate; assign snp_fwdout_tag[i] = sfq_write_addr; end assign snp_req_ready = !sfq_full && fwdout_ready; if (NUM_REQUESTS > 1) begin wire sel_valid; wire [`REQS_BITS-1:0] sel_idx; wire [NUM_REQUESTS-1:0] sel_1hot; VX_rr_arbiter #( .N(NUM_REQUESTS) ) sel_arb ( .clk (clk), .reset (reset), .requests (snp_fwdin_valid), .grant_valid (sel_valid), .grant_index (sel_idx), .grant_onehot (sel_1hot) ); wire stall = ~fwdin_ready && fwdin_valid; VX_generic_register #( .N(1 + `LOG2UP(SNRQ_SIZE)), .PASSTHRU(NUM_REQUESTS <= 2) ) pipe_reg ( .clk (clk), .reset (reset), .stall (stall), .flush (1'b0), .in ({sel_valid, snp_fwdin_tag[sel_idx]}), .out ({fwdin_valid, fwdin_tag}) ); for (genvar i = 0; i < NUM_REQUESTS; i++) begin assign snp_fwdin_ready[i] = sel_1hot[i] && !stall; end end else begin assign fwdin_valid = snp_fwdin_valid; assign fwdin_tag = snp_fwdin_tag; assign snp_fwdin_ready = fwdin_ready; end `ifdef DBG_PRINT_CACHE_SNP always @(posedge clk) begin if (snp_req_valid && snp_req_ready) begin $display("%t: cache%0d snp-fwd-req: addr=%0h, invalidate=%0d, tag=%0h", $time, CACHE_ID, `DRAM_TO_BYTE_ADDR(snp_req_addr), snp_req_invalidate, snp_req_tag); end if (snp_fwdout_valid[0] && snp_fwdout_ready[0]) begin $display("%t: cache%0d snp-fwd-out: addr=%0h, invalidate=%0d, tag=%0h", $time, CACHE_ID, `DRAM_TO_BYTE_ADDR(snp_fwdout_addr[0]), snp_fwdout_invalidate[0], snp_fwdout_tag[0]); end if (fwdin_valid && fwdin_ready) begin $display("%t: cache%0d snp-fwd-in: tag=%0h", $time, CACHE_ID, fwdin_tag); end if (snp_rsp_valid && snp_rsp_ready) begin $display("%t: cache%0d snp-fwd-rsp: addr=%0h, invalidate=%0d, tag=%0h", $time, CACHE_ID, snp_rsp_addr, snp_rsp_invalidate, snp_rsp_tag); end end `endif endmodule