// Cache Memory (8way 4word) // // i_ means input port // // o_ means output port // // _p_ means data exchange with processor // // _m_ means data exchange with memory // // TO DO: // - Send in a response from memory of what the data is from the test bench `include "../VX_define.v" //`include "VX_priority_encoder.v" // `include "VX_Cache_Bank.v" //`include "cache_set.v" module VX_d_cache #( parameter CACHE_SIZE = 4096, // Bytes parameter CACHE_WAYS = 1, parameter CACHE_BLOCK = 128, // Bytes parameter CACHE_BANKS = 8, parameter LOG_NUM_BANKS = 3, parameter NUM_REQ = 8, parameter LOG_NUM_REQ = 3, parameter NUM_IND = 8, parameter CACHE_WAY_INDEX = 1, parameter NUM_WORDS_PER_BLOCK = 4, parameter OFFSET_SIZE_START = 0, parameter OFFSET_SIZE_END = 1, parameter TAG_SIZE_START = 0, parameter TAG_SIZE_END = 16, parameter IND_SIZE_START = 0, parameter IND_SIZE_END = 7, parameter ADDR_TAG_START = 15, parameter ADDR_TAG_END = 31, parameter ADDR_OFFSET_START = 5, parameter ADDR_OFFSET_END = 6, parameter ADDR_IND_START = 7, parameter ADDR_IND_END = 14, parameter MEM_ADDR_REQ_MASK = 32'hffffffc0 ) ( clk, rst, i_p_addr, //i_p_byte_en, i_p_writedata, i_p_read_or_write, // 0 = Read | 1 = Write i_p_mem_read, i_p_mem_write, i_p_valid, //i_p_write, o_p_readdata, o_p_delay, // 0 = all threads done | 1 = Still threads that need to o_m_evict_addr, o_m_read_addr, o_m_writedata, o_m_read_or_write, // 0 = Read | 1 = Write o_m_valid, i_m_readdata, i_m_ready ); //parameter NUMBER_BANKS = `CACHE_BANKS; //localparam NUM_WORDS_PER_BLOCK = `CACHE_BLOCK / (`CACHE_BANKS*4); //localparam CACHE_BLOCK_PER_BANK = (`CACHE_BLOCK / `CACHE_BANKS); localparam CACHE_IDLE = 0; // Idle localparam SEND_MEM_REQ = 1; // Write back this block into memory localparam RECIV_MEM_RSP = 2; //parameter cache_entry = 9; input wire clk, rst; input wire [NUM_REQ-1:0] i_p_valid; input wire [NUM_REQ-1:0][31:0] i_p_addr; // FIXME input wire [NUM_REQ-1:0][31:0] i_p_writedata; input wire i_p_read_or_write; //, i_p_write; output reg [NUM_REQ-1:0][31:0] o_p_readdata; output wire o_p_delay; output reg [31:0] o_m_evict_addr; // Address is xxxxxxxxxxoooobbbyy output reg [31:0] o_m_read_addr; output reg o_m_valid; output reg[CACHE_BANKS - 1:0][NUM_WORDS_PER_BLOCK-1:0][31:0] o_m_writedata; output reg o_m_read_or_write; //, o_m_write; input wire[CACHE_BANKS - 1:0][NUM_WORDS_PER_BLOCK-1:0][31:0] i_m_readdata; input wire i_m_ready; input wire[2:0] i_p_mem_read; input wire[2:0] i_p_mem_write; // Buffer for final data reg [NUM_REQ-1:0][31:0] final_data_read; reg [NUM_REQ-1:0][31:0] new_final_data_read; wire[NUM_REQ-1:0][31:0] new_final_data_read_Qual; assign o_p_readdata = new_final_data_read_Qual; reg[CACHE_WAY_INDEX-1:0] global_way_to_evict; wire[CACHE_BANKS - 1 : 0][NUM_REQ-1:0] thread_track_banks; // Valid thread mask per bank wire[CACHE_BANKS - 1 : 0][LOG_NUM_REQ-1:0] index_per_bank; // Index of thread each bank will try to service wire[CACHE_BANKS - 1 : 0][NUM_REQ-1:0] use_mask_per_bank; // A mask of index_per_bank wire[CACHE_BANKS - 1 : 0] valid_per_bank; // Valid request going to each bank wire[CACHE_BANKS - 1 : 0][NUM_REQ-1:0] threads_serviced_per_bank; // Bank successfully serviced per bank wire[CACHE_BANKS-1:0][31:0] readdata_per_bank; // Data read from each bank wire[CACHE_BANKS-1:0] hit_per_bank; // Whether each bank got a hit or a miss wire[CACHE_BANKS-1:0] eviction_wb; reg[CACHE_BANKS-1:0] eviction_wb_old; // wire[CACHE_BANKS -1 : 0][CACHE_WAY_INDEX-1:0] evicted_way_new; // reg [CACHE_BANKS -1 : 0][CACHE_WAY_INDEX-1:0] evicted_way_old; // wire[CACHE_BANKS -1 : 0][CACHE_WAY_INDEX-1:0] way_used; // Internal State reg [3:0] state; wire[3:0] new_state; wire[NUM_REQ-1:0] use_valid; // Valid used throught the code reg[NUM_REQ-1:0] stored_valid; // Saving the threads still left (bank conflict or bank miss) wire[NUM_REQ-1:0] new_stored_valid; // New stored valid reg[CACHE_BANKS - 1 : 0][31:0] eviction_addr_per_bank; reg[31:0] miss_addr; // reg[31:0] evict_addr; wire curr_processor_request_valid = (|i_p_valid); assign use_valid = (stored_valid == 0) ? i_p_valid : stored_valid; VX_cache_bank_valid #(.NUMBER_BANKS (CACHE_BANKS), .LOG_NUM_BANKS (LOG_NUM_BANKS), .NUM_REQ (NUM_REQ)) multip_banks( .i_p_valid (use_valid), .i_p_addr (i_p_addr), .thread_track_banks(thread_track_banks) ); reg[NUM_REQ-1:0] threads_serviced_Qual; reg[NUM_REQ-1:0] debug_hit_per_bank_mask[CACHE_BANKS-1:0]; genvar bid; for (bid = 0; bid < CACHE_BANKS; bid=bid+1) begin wire[NUM_REQ-1:0] use_threads_track_banks = thread_track_banks[bid]; wire[LOG_NUM_REQ-1:0] use_thread_index = index_per_bank[bid]; wire use_write_final_data = hit_per_bank[bid]; wire[31:0] use_data_final_data = readdata_per_bank[bid]; VX_priority_encoder_w_mask #(.N(NUM_REQ)) choose_thread( .valids(use_threads_track_banks), .mask (use_mask_per_bank[bid]), .index (index_per_bank[bid]), .found (valid_per_bank[bid]) ); assign debug_hit_per_bank_mask[bid] = {NUM_REQ{hit_per_bank[bid]}}; assign threads_serviced_per_bank[bid] = use_mask_per_bank[bid] & debug_hit_per_bank_mask[bid]; end integer test_bid; always @(*) begin new_final_data_read = 0; for (test_bid=0; test_bid < CACHE_BANKS; test_bid=test_bid+1) begin if (hit_per_bank[test_bid]) begin new_final_data_read[index_per_bank[test_bid]] = readdata_per_bank[test_bid]; end end end wire[CACHE_BANKS - 1 : 0] detect_bank_miss; //assign threads_serviced_Qual = threads_serviced_per_bank[0] | threads_serviced_per_bank[1] | // threads_serviced_per_bank[2] | threads_serviced_per_bank[3] | // threads_serviced_per_bank[4] | threads_serviced_per_bank[5] | // threads_serviced_per_bank[6] | threads_serviced_per_bank[7]; integer bbid; always @(*) begin threads_serviced_Qual = 0; for (bbid = 0; bbid < CACHE_BANKS; bbid=bbid+1) begin threads_serviced_Qual = threads_serviced_Qual | threads_serviced_per_bank[bbid]; end end genvar tid; for (tid = 0; tid < NUM_REQ; tid =tid+1) begin assign new_final_data_read_Qual[tid] = threads_serviced_Qual[tid] ? new_final_data_read[tid] : final_data_read[tid]; end assign detect_bank_miss = (valid_per_bank & ~hit_per_bank); wire delay; assign delay = (new_stored_valid != 0) || (state != CACHE_IDLE); // add other states assign o_p_delay = delay; wire[CACHE_BANKS - 1 : 0][LOG_NUM_REQ-1:0] send_index_to_bank = index_per_bank; wire[LOG_NUM_BANKS-1:0] miss_bank_index; wire miss_found; VX_generic_priority_encoder #(.N(CACHE_BANKS)) get_miss_index ( .valids(detect_bank_miss), .index (miss_bank_index), .found (miss_found) ); assign new_state = ((state == CACHE_IDLE) && (|detect_bank_miss)) ? SEND_MEM_REQ : (state == SEND_MEM_REQ) ? RECIV_MEM_RSP : ((state == RECIV_MEM_RSP) && !i_m_ready) ? RECIV_MEM_RSP : CACHE_IDLE; // Handle if there is more than one miss assign new_stored_valid = use_valid & (~threads_serviced_Qual); wire update_global_way_to_evict = ((state == RECIV_MEM_RSP) && (new_state == CACHE_IDLE) && (CACHE_WAYS)) && (CACHE_WAYS > 1); /////////////////////////////////////////////////////////////////////// genvar cur_t; integer init_b; always @(posedge clk, posedge rst) begin if (rst) begin final_data_read <= 0; // new_final_data_read = 0; state <= 0; stored_valid <= 0; // eviction_addr_per_bank <= 0; miss_addr <= 0; // evict_addr <= 0; // threads_serviced_Qual = 0; // for (init_b = 0; init_b < NUMBER_BANKS; init_b=init_b+1) // begin // debug_hit_per_bank_mask[init_b] <= 0; // end // evicted_way_old <= 0; // eviction_wb_old <= 0; global_way_to_evict <= 0; end else begin global_way_to_evict <= (update_global_way_to_evict) ? (global_way_to_evict+1) : global_way_to_evict; state <= new_state; stored_valid <= new_stored_valid; if (state == CACHE_IDLE) begin if (miss_found) begin miss_addr <= i_p_addr[send_index_to_bank[miss_bank_index]]; // evict_addr <= eviction_addr_per_bank[miss_bank_index]; end else begin miss_addr <= 0; // evict_addr <= 0; end end final_data_read <= new_final_data_read_Qual; // evicted_way_old <= evicted_way_new; // eviction_wb_old <= eviction_wb; end end genvar bank_id; generate for (bank_id = 0; bank_id < CACHE_BANKS; bank_id = bank_id + 1) begin wire[31:0] bank_addr = (state == SEND_MEM_REQ) ? miss_addr : (state == RECIV_MEM_RSP) ? miss_addr : i_p_addr[send_index_to_bank[bank_id]]; // assign evicted_way_new[bank_id] = (state == SEND_MEM_REQ) ? way_used[bank_id] : // (state == RECIV_MEM_RSP) ? evicted_way_old[bank_id] : // 0; wire[1:0] byte_select = bank_addr[1:0]; wire[OFFSET_SIZE_END:OFFSET_SIZE_START] cache_offset = bank_addr[ADDR_OFFSET_END:ADDR_OFFSET_START]; wire[IND_SIZE_END:IND_SIZE_START] cache_index = bank_addr[ADDR_IND_END:ADDR_IND_START]; wire[TAG_SIZE_END:TAG_SIZE_START] cache_tag = bank_addr[ADDR_TAG_END:ADDR_TAG_START]; wire normal_valid_in = valid_per_bank[bank_id]; wire use_valid_in = ((state == RECIV_MEM_RSP) && i_m_ready) ? 1'b1 : ((state == RECIV_MEM_RSP) && !i_m_ready) ? 1'b0 : ((state == SEND_MEM_REQ)) ? 1'b0 : normal_valid_in; VX_Cache_Bank #( .CACHE_SIZE (CACHE_SIZE), .CACHE_WAYS (CACHE_WAYS), .CACHE_BLOCK (CACHE_BLOCK), .CACHE_BANKS (CACHE_BANKS), .LOG_NUM_BANKS (LOG_NUM_BANKS), .NUM_REQ (NUM_REQ), .LOG_NUM_REQ (LOG_NUM_REQ), .NUM_IND (NUM_IND), .CACHE_WAY_INDEX (CACHE_WAY_INDEX), .NUM_WORDS_PER_BLOCK (NUM_WORDS_PER_BLOCK), .OFFSET_SIZE_START (OFFSET_SIZE_START), .OFFSET_SIZE_END (OFFSET_SIZE_END), .TAG_SIZE_START (TAG_SIZE_START), .TAG_SIZE_END (TAG_SIZE_END), .IND_SIZE_START (IND_SIZE_START), .IND_SIZE_END (IND_SIZE_END), .ADDR_TAG_START (ADDR_TAG_START), .ADDR_TAG_END (ADDR_TAG_END), .ADDR_OFFSET_START (ADDR_OFFSET_START), .ADDR_OFFSET_END (ADDR_OFFSET_END), .ADDR_IND_START (ADDR_IND_START), .ADDR_IND_END (ADDR_IND_END) ) bank_structure ( .clk (clk), .rst (rst), .state (state), .valid_in (use_valid_in), .actual_index (cache_index), .o_tag (cache_tag), .block_offset (cache_offset), .writedata (i_p_writedata[send_index_to_bank[bank_id]]), .read_or_write (i_p_read_or_write), .i_p_mem_read (i_p_mem_read), .i_p_mem_write (i_p_mem_write), .byte_select (byte_select), .hit (hit_per_bank[bank_id]), .readdata (readdata_per_bank[bank_id]), // Data read .eviction_addr (eviction_addr_per_bank[bank_id]), .data_evicted (o_m_writedata[bank_id]), .eviction_wb (eviction_wb[bank_id]), // Something needs to be written back .fetched_writedata(i_m_readdata[bank_id]), // Data From memory .evicted_way (global_way_to_evict) ); end endgenerate // Mem Rsp // Req to mem: assign o_m_evict_addr = (eviction_addr_per_bank[0]) & MEM_ADDR_REQ_MASK; // Could be anything because tag+index are same assign o_m_read_addr = miss_addr & MEM_ADDR_REQ_MASK; assign o_m_valid = (state == SEND_MEM_REQ); assign o_m_read_or_write = (state == SEND_MEM_REQ) && (|eviction_wb); //end endmodule