Files
2026-04-12 22:20:18 +08:00

411 lines
14 KiB
Verilog

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