module icache ( input clk , input reset , //to from cpu input valid , input op , input [ 7:0] index , input [19:0] tag , input [ 3:0] offset , input [ 3:0] wstrb , input [31:0] wdata , output addr_ok , output data_ok , output [31:0] rdata , input uncache_en , input icacop_op_en , input [ 1:0] cacop_op_mode , input [ 7:0] cacop_op_addr_index , //this signal from mem stage's va input [19:0] cacop_op_addr_tag , input [ 3:0] cacop_op_addr_offset, output icache_unbusy, input tlb_excp_cancel_req, //to from axi output rd_req , output [ 2:0] rd_type , output [31:0] rd_addr , input rd_rdy , input ret_valid , input ret_last , input [31:0] ret_data , output reg wr_req , output [ 2:0] wr_type , output [31:0] wr_addr , output [ 3:0] wr_wstrb , output [127:0] wr_data , input wr_rdy , //to perf_counter output cache_miss ); reg request_buffer_op ; reg [ 7:0] request_buffer_index ; reg [19:0] request_buffer_tag ; reg [ 3:0] request_buffer_offset ; reg [ 3:0] request_buffer_wstrb ; reg [31:0] request_buffer_wdata ; reg request_buffer_uncache_en ; reg request_buffer_icacop ; reg [ 1:0] request_buffer_cacop_op_mode; reg [ 1:0] miss_buffer_replace_way ; reg [ 1:0] miss_buffer_ret_num ; wire [ 1:0] ret_num_add_one ; wire [ 7:0] way_bank_addra [1:0][3:0]; wire [31:0] way_bank_dina [1:0][3:0]; wire [31:0] way_bank_douta [1:0][3:0]; wire way_bank_ena [1:0][3:0]; wire [ 3:0] way_bank_wea [1:0][3:0]; wire [ 7:0] way_tagv_addra [1:0]; wire [20:0] way_tagv_dina [1:0]; wire [20:0] way_tagv_douta [1:0]; wire way_tagv_ena [1:0]; wire way_tagv_wea [1:0]; wire [ 1:0] way_hit ; wire cache_hit ; wire [ 31:0] way_load_word [1:0]; wire [127:0] way_data [1:0]; wire [31:0] load_res ; wire main_idle2lookup ; wire main_lookup2lookup; wire main_state_is_idle ; wire main_state_is_lookup ; wire main_state_is_replace; wire main_state_is_refill ; wire [1:0] way_wr_en; wire [31:0] refill_data; wire cacop_op_mode0; wire cacop_op_mode1; wire cacop_op_mode2; wire [1:0] random_val; wire [3:0] chosen_way; wire [1:0] replace_way; wire [1:0] invalid_way; wire has_invalid_way; wire [1:0] rand_repl_way; wire [3:0] cacop_chose_way; wire cacop_op_mode2_hit_wr; wire cacop_op_mode2_no_hit; reg [ 1:0] lookup_way_hit_buffer; wire [ 3:0] real_offset; wire [19:0] real_tag ; wire [ 7:0] real_index ; wire req_or_inst_valid ; localparam main_idle = 5'b00001; localparam main_lookup = 5'b00010; localparam main_replace = 5'b01000; localparam main_refill = 5'b10000; localparam write_buffer_idle = 1'b0; localparam write_buffer_write = 1'b1; reg [4:0] main_state; reg rd_req_buffer; genvar i,j; //state machine //main loop always @(posedge clk) begin if (reset) begin main_state <= main_idle; request_buffer_op <= 1'b0; request_buffer_index <= 8'b0; request_buffer_tag <= 20'b0; request_buffer_offset <= 4'b0; request_buffer_wstrb <= 4'b0; request_buffer_wdata <= 32'b0; request_buffer_uncache_en <= 1'b0; request_buffer_cacop_op_mode <= 2'b0; request_buffer_icacop <= 1'b0; miss_buffer_replace_way <= 2'b0; wr_req <= 1'b0; end else case (main_state) main_idle: begin if (req_or_inst_valid && main_idle2lookup) begin main_state <= main_lookup; request_buffer_op <= op ; request_buffer_index <= real_index ; request_buffer_offset <= real_offset; request_buffer_wstrb <= wstrb; request_buffer_wdata <= wdata; request_buffer_cacop_op_mode <= cacop_op_mode; request_buffer_icacop <= icacop_op_en ; end end main_lookup: begin if (req_or_inst_valid && main_lookup2lookup) begin main_state <= main_lookup; request_buffer_op <= op ; request_buffer_index <= real_index ; request_buffer_offset <= real_offset; request_buffer_wstrb <= wstrb; request_buffer_wdata <= wdata; request_buffer_cacop_op_mode <= cacop_op_mode; request_buffer_icacop <= icacop_op_en ; end else if (tlb_excp_cancel_req) begin main_state <= main_idle; end else if (!cache_hit) begin main_state <= main_replace; request_buffer_tag <= real_tag; request_buffer_uncache_en <= (uncache_en && !request_buffer_icacop); miss_buffer_replace_way <= replace_way; end else begin main_state <= main_idle; end end main_replace: begin if (rd_rdy) begin main_state <= main_refill; miss_buffer_ret_num <= 2'b0; //when get ret data, it will be sent to cpu directly. end end main_refill: begin if ((ret_valid && ret_last) || !rd_req_buffer) begin //when rd_req is not set, go to next state directly main_state <= main_idle; end else begin if (ret_valid) begin miss_buffer_ret_num <= ret_num_add_one; end end end default: begin main_state <= main_idle; end endcase end assign real_offset = icacop_op_en ? cacop_op_addr_offset : offset; assign real_index = icacop_op_en ? cacop_op_addr_index : index ; assign real_tag = request_buffer_icacop ? cacop_op_addr_tag : tag ; /*====================================main state idle=======================================*/ assign req_or_inst_valid = valid || icacop_op_en; assign main_idle2lookup = 1'b1; assign icache_unbusy = main_state_is_idle; //addr_ok logic /*===================================main state lookup======================================*/ //tag compare generate for(i=0;i<2;i=i+1) begin:gen_way_hit assign way_hit[i] = way_tagv_douta[i][0] && (real_tag == way_tagv_douta[i][20:1]); //this signal will not maintain end endgenerate assign cache_hit = |way_hit && !(uncache_en || cacop_op_mode0 || cacop_op_mode1 || cacop_op_mode2); //uncache road reuse //when cache inst op mode2 no hit, main state machine will still go a round. implement easy. assign main_lookup2lookup = cache_hit; assign addr_ok = ((main_state_is_idle && main_idle2lookup) || (main_state_is_lookup && main_lookup2lookup)) && !icacop_op_en; //request can be get //data select generate for(i=0;i<2;i=i+1) begin: gen_data assign way_data[i] = {way_bank_douta[i][3],way_bank_douta[i][2],way_bank_douta[i][1],way_bank_douta[i][0]}; assign way_load_word[i] = way_data[i][request_buffer_offset[3:2]*32 +: 32]; end endgenerate assign load_res = {32{way_hit[0]}} & way_load_word[0] | {32{way_hit[1]}} & way_load_word[1] ; //data_ok logic /*====================================main state miss=======================================*/ decoder_2_4 dec_rand_way (.in({1'b0,random_val[0]}),.out(chosen_way)); one_valid_n #(2) sel_one_invalid (.in(~{way_tagv_douta[1][0],way_tagv_douta[0][0]}),.out(invalid_way),.nozero(has_invalid_way)); assign rand_repl_way = has_invalid_way ? invalid_way : chosen_way[1:0]; //chose invalid way first. decoder_2_4 dec_cacop_way (.in({1'b0,request_buffer_offset[0]}),.out(cacop_chose_way)); assign replace_way = {2{cacop_op_mode0 || cacop_op_mode1}} & cacop_chose_way[1:0] | {2{cacop_op_mode2}} & way_hit | {2{!request_buffer_icacop}} & rand_repl_way; /*==================================main state replace======================================*/ assign rd_req = main_state_is_replace && !(cacop_op_mode0 || cacop_op_mode1 || cacop_op_mode2); /*===================================main state refill======================================*/ assign rd_type = request_buffer_uncache_en ? 3'b10 : 3'b100; assign rd_addr = request_buffer_uncache_en ? {request_buffer_tag, request_buffer_index, request_buffer_offset} : {request_buffer_tag, request_buffer_index, 4'b0}; //write process will not block pipeline assign data_ok = (main_state_is_lookup && (cache_hit || tlb_excp_cancel_req)) || (main_state_is_refill && ((ret_valid && ((miss_buffer_ret_num == request_buffer_offset[3:2]) || request_buffer_uncache_en))/* || !rd_req_buffer*/)) && !request_buffer_icacop; //when rd_req is not set, set data_ok directly. //rdate connect with ret_data dirctly. maintain one clock only assign refill_data = ret_data; assign way_wr_en = miss_buffer_replace_way & {2{ret_valid}}; //when rd_req is not set, ret_valid and ret_last will not be set. block will not be wr also. assign cache_miss = main_state_is_refill && ret_last && !(request_buffer_uncache_en || request_buffer_icacop); //add one assign ret_num_add_one[0] = miss_buffer_ret_num[0] ^ 1'b1; assign ret_num_add_one[1] = miss_buffer_ret_num[1] ^ miss_buffer_ret_num[0]; always @(posedge clk) begin if (reset) begin rd_req_buffer <= 1'b0; end else if (rd_req) begin rd_req_buffer <= 1'b1; end else if (main_state_is_refill && (ret_valid && ret_last)) begin rd_req_buffer <= 1'b0; end end /*==========================================================================================*/ //cache ins control signal assign cacop_op_mode0 = request_buffer_icacop && (request_buffer_cacop_op_mode == 2'b00); assign cacop_op_mode1 = request_buffer_icacop && ((request_buffer_cacop_op_mode == 2'b01) || (request_buffer_cacop_op_mode == 2'b11)); assign cacop_op_mode2 = request_buffer_icacop && (request_buffer_cacop_op_mode == 2'b10); assign cacop_op_mode2_hit_wr = cacop_op_mode2 && |lookup_way_hit_buffer; assign cacop_op_mode2_no_hit = cacop_op_mode2 && ~|lookup_way_hit_buffer; always @(posedge clk) begin if (reset) begin lookup_way_hit_buffer <= 2'b0; end else if (cacop_op_mode2 && main_state_is_lookup) begin lookup_way_hit_buffer <= way_hit; end end //output assign rdata = {32{main_state_is_lookup}} & load_res | {32{main_state_is_refill}} & ret_data ; generate for(i=0;i<2;i=i+1) begin:gen_data_way for(j=0;j<4;j=j+1) begin:gen_data_bank /*===============================bank addra logic==============================*/ assign way_bank_addra[i][j] = {8{addr_ok}} & real_index | /*lookup*/ {8{!addr_ok}} & request_buffer_index ; /*===============================bank we logic=================================*/ assign way_bank_wea[i][j] = {4{main_state_is_refill && (way_wr_en[i] && (miss_buffer_ret_num == j[1:0]))}} & 4'hf; /*===============================bank dina logic=================================*/ assign way_bank_dina[i][j] = {32{main_state_is_refill}} & refill_data; /*===============================bank ena logic=================================*/ assign way_bank_ena[i][j] = (!(request_buffer_uncache_en || cacop_op_mode0)) || main_state_is_idle || main_state_is_lookup; end end endgenerate generate for(i=0;i<2;i=i+1) begin:gen_tagv_way /*===============================tagv addra logic=================================*/ assign way_tagv_addra[i] = {8{addr_ok || (icacop_op_en && (main_state_is_idle || main_state_is_lookup))}} & real_index | {8{main_state_is_replace || main_state_is_refill}} & request_buffer_index ; //{8{(main_state_is_miss && wr_rdy) || /*===============================tagv ena logic=================================*/ assign way_tagv_ena[i] = (!request_buffer_uncache_en) || main_state_is_idle || main_state_is_lookup; /*===============================tagv wea logic=================================*/ assign way_tagv_wea[i] = miss_buffer_replace_way[i] && main_state_is_refill && ((ret_valid && ret_last) || cacop_op_mode0 || cacop_op_mode1 || cacop_op_mode2_hit_wr); //wirte at last 4B /*===============================tagv dina logic=================================*/ assign way_tagv_dina[i] = (cacop_op_mode0 || cacop_op_mode1 || cacop_op_mode2_hit_wr) ? 21'b0 : {request_buffer_tag, 1'b1}; end endgenerate /*==============================================================================*/ generate for(i=0;i<2;i=i+1) begin:data_ram_way for(j=0;j<4;j=j+1) begin:data_ram_bank data_bank_sram u( .addra (way_bank_addra[i][j]) , .clka (clk ) , .dina (way_bank_dina[i][j] ) , .douta (way_bank_douta[i][j]) , .ena (way_bank_ena[i][j] ) , .wea (way_bank_wea[i][j] ) ); end end endgenerate generate for(i=0;i<2;i=i+1) begin:tagv_ram_way //[20:1] tag [0:0] v tagv_sram u( .addra (way_tagv_addra[i]) , .clka (clk ) , .dina (way_tagv_dina[i] ) , .douta (way_tagv_douta[i]) , .ena (way_tagv_ena[i] ) , .wea (way_tagv_wea[i] ) ); end endgenerate lfsr lfsr( .clk (clk ) , .reset (reset ) , .random_val (random_val ) ); assign main_state_is_idle = main_state == main_idle ; assign main_state_is_lookup = main_state == main_lookup ; assign main_state_is_replace = main_state == main_replace; assign main_state_is_refill = main_state == main_refill ; endmodule