module application_wrapper_cache_miss_handler #( parameter NUM_WAYS = 4, parameter NUM_SETS = 64, localparam CPU_W = 8, localparam DATA_W = 64*8, localparam OFFSET_W = 6, localparam INDEX_W = $clog2(NUM_SETS), localparam TAG_W = 32 - INDEX_W - OFFSET_W, localparam LRU_W = NUM_WAYS-1 localparam META_W = TAG_W + 2 ) ( input logic i_clk, input logic i_rst, // NOTE: tag is physical tag, expected 1 cycle after the index and the offset input logic [TAG_W-1:0] i_cpu_tag, input logic [INDEX_W-1:0] i_cpu_index, input logic [OFFSET_W-1:0] i_cpu_offset, input logic i_rdy, output logic o_rdy, input logic i_cpu_we, input logic [CPU_W-1:0] i_cpu_data, output logic [CPU_W-1:0] o_cpu_data, output logic [INDEX_W-1:0] o_read_index, output logic o_read_valid, input logic [DATA_W-1:0] i_read_data [NUM_WAYS], input logic [META_W-1:0] i_read_meta [NUM_WAYS], output logic [INDEX_W-1:0] o_write_index, output logic [NUM_WAYS-1:0] o_write_valid, output logic [DATA_W-1:0] o_write_data, output logic [META_W-1:0] o_write_meta, output logic [INDEX_W-1:0] o_lru_read_index, output logic o_lru_read_valid, input logic [LRU_W-1:0]] i_lru_read_data, output logic [INDEX_W-1:0] o_lru_write_index, output logic o_lru_write_valid, output logic [LRU_W-1:0]] o_lru_write_data, ); enum logic [3:0] { IDLE, CHECK_VICTIM, WRITEBACK, WAIT_WRITEBACK_ACK, REQUEST_MEMORY, WAIT_MEMORY, INSTALL_LINE, UPDATE_LRU, REQUEST_OWNERSHIP } state, state_next; logic cpu_we_d1; logic cpu_i_data_d1; logic [INDEX_W-1:0] cpu_index_d1; logic [OFFSET_W-1:0] cpu_offset_d1; logic way_match_found; logic [NUM_WAYS-1:0] way_select_mask; mesi_e mesi; logic [TAG_W-1:0] tag; always_ff @(posedge i_clk) begin if (i_rst) begin state <= IDLE; end else begin state <= state_next; end cpu_we_d1 <= i_cpu_we; cpu_i_data_d1 <= i_cpu_data cpu_index_d1 <= i_cpu_index; cpu_offset_d1 <= i_cpu_offset; end always_comb begin o_rdy = '0; o_cpu_data = '0; o_read_valid = '0; o_read_index = '0; o_write_valid = '0; o_write_index = '0; o_write_data = '0; o_write_meta = '0; o_lru_read_valid = '0; o_lru_read_index = '0; o_lru_write_valid = '0; o_lru_write_index = '0; o_lru_write_data = '0; state_next = state; case (state) IDLE: begin // by default, o_rdy is 1 unless something is wrong o_rdy = '1; // Read from arrays o_read_index = i_cpu_index; o_read_valid = i_rdy; o_lru_read_index = i_cpu_index; o_lru_read_valid = i_rdy; // data from previous cycle that was read from arrays way_match_found = '0; way_select_mask = '0; for (int i; i < NUM_WAYS; i++) begin {mesi, tag} = i_read_meta[i]; if (tag == i_cpu_tag && mesi != MESI_INVALID) begin way_match_found = '1; way_select_mask[i] = '1; break; end end // We have a match, so either read or write data if (way_match_found) begin if (cpu_we_d1) begin // write data back to the cache array // check if we are in the M or E states before we write. // If we are in S then we need to request ownership before // we can modify it. if (mesi == MESI_MODIFIED || mesi == MESI_EXCLUSIVE) begin o_write_data = i_read_data; o_write_data[cpu_offset_d1 +: 8] = cpu_i_data_d1; o_write_meta = {MESI_MODIFIED, i_cpu_tag}; o_write_valid = way_select_mask; o_write_index = cpu_index_d1; end else begin o_rdy = '0; state_next = REQUEST_OWNERSHIP; end end else begin // Send the data to the CPU o_cpu_data = i_read_data[cpu_offset_d1 +: 8]; end // update lru // start by copying the read data, then change the bits // based on what we matched. o_lru_write_index = cpu_index_d1; o_lru_write_data = i_lru_read_data; o_lru_write_valid = '1; case (way_select_mask) 4'b0001: begin o_lru_write_data[0] = '1; o_lru_write_data[1] = '1; end 4'b0010: begin o_lru_write_data[0] = '1; o_lru_write_data[1] = '0; end 4'b0100: begin o_lru_write_data[0] = '0; o_lru_write_data[2] = '1; end 4'b1000: begin o_lru_write_data[0] = '0; o_lru_write_data[2] = '0; end endcase end end default: begin end endcase end