// Copyright 2018 ETH Zurich, University of Bologna and Greenwaves Technologies.
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
/*icache_controller_private.sv */
`define USE_REQ_BUFFER
`define log2_non_zero(VALUE) ((VALUE) < ( 1 ) ? 1 : (VALUE) < ( 2 ) ? 1 : (VALUE) < ( 4 ) ? 2 : (VALUE)< (8) ? 3:(VALUE) < ( 16 ) ? 4 : (VALUE) < ( 32 ) ? 5 : (VALUE) < ( 64 ) ? 6 : (VALUE) < ( 128 ) ? 7 : (VALUE) < ( 256 ) ? 8 : (VALUE) < ( 512 ) ? 9 : 10)
module dcache_controller_private
#(
parameter FETCH_ADDR_WIDTH = 32,
parameter FETCH_DATA_WIDTH = 32,
parameter NB_WAYS = 4,
parameter CACHE_LINE = 4,
parameter SCM_TAG_ADDR_WIDTH = 4,
parameter SCM_DATA_ADDR_WIDTH = 6,
parameter SCM_TAG_WIDTH = 8,
parameter SCM_DATA_WIDTH = 128,
parameter SCM_NUM_ROWS = 2**SCM_TAG_ADDR_WIDTH,
parameter SET_ID_LSB = $clog2(SCM_DATA_WIDTH*CACHE_LINE)-3,
parameter SET_ID_MSB = SET_ID_LSB + SCM_TAG_ADDR_WIDTH - 1,
parameter TAG_LSB = SET_ID_MSB + 1,
parameter TAG_MSB = TAG_LSB + SCM_TAG_WIDTH - 2,
parameter AXI_ID = 4,
parameter AXI_ADDR = FETCH_ADDR_WIDTH,
parameter AXI_USER = 6,
parameter AXI_DATA = 32
)
(
input logic clk,
input logic rst_n,
input logic test_en_i,
input logic bypass_icache_i,
output logic cache_is_bypassed_o,
input logic flush_icache_i,
output logic cache_is_flushed_o,
input logic flush_set_ID_req_i,
input logic [FETCH_ADDR_WIDTH-1:0] flush_set_ID_addr_i,
output logic flush_set_ID_ack_o,
// interface with processor
input logic fetch_req_i,
input logic [FETCH_ADDR_WIDTH-1:0] fetch_addr_i,
output logic fetch_gnt_o,
output logic fetch_rvalid_o,
output logic [FETCH_DATA_WIDTH-1:0] fetch_rdata_o,
input logic fetch_we_i,
input logic [FETCH_DATA_WIDTH-1:0] fetch_wdata_i,
// interface with READ PORT --> SCM DATA
output logic [NB_WAYS-1:0] DATA_req_o,
output logic DATA_we_o,
output logic [SCM_DATA_ADDR_WIDTH-1:0] DATA_addr_o,
input logic [NB_WAYS-1:0][SCM_DATA_WIDTH-1:0] DATA_rdata_i,
output logic [FETCH_DATA_WIDTH-1:0] DATA_wdata_o,
input logic [NB_WAYS-1:0] DATA_error_i,
output logic [NB_WAYS-1:0] DATA_need_correct_o,
// interface with READ PORT --> SCM TAG
output logic [NB_WAYS-1:0] TAG_req_o,
output logic [SCM_TAG_ADDR_WIDTH-1:0] TAG_addr_o,
input logic [NB_WAYS-1:0][SCM_TAG_WIDTH-1:0] TAG_rdata_i,
output logic [SCM_TAG_WIDTH-1:0] TAG_wdata_o,
output logic TAG_we_o,
// Interface to cache_controller_to_axi
output logic axi_ar_valid_o,
input logic axi_ar_ready_i,
output logic [AXI_ADDR-1:0] axi_ar_addr_o,
output logic [7:0] axi_ar_len_o,
input logic axi_r_valid_i,
output logic axi_r_ready_o,
input logic [AXI_DATA-1:0] axi_r_data_i,
input logic axi_r_last_i,
output logic [AXI_ADDR-1:0] axi_aw_addr_o,
output logic [ 7:0] axi_aw_len_o,
output logic axi_aw_valid_o,
input logic axi_aw_ready_i,
output logic [AXI_DATA-1:0] axi_w_data_o,
output logic axi_w_last_o,
output logic axi_w_valid_o,
input logic axi_w_ready_i,
input logic axi_b_valid_i,
output logic axi_b_ready_o,
output logic [31:0] ctrl_hit_count_icache_o,
output logic [31:0] ctrl_trans_count_icache_o,
output logic [31:0] ctrl_miss_count_icache_o,
input logic ctrl_clear_regs_icache_i,
input logic ctrl_enable_regs_icache_i,
output logic [31:0] ref_count_o,
output logic [31:0] err_count_o,
output logic [31:0] cycle_count_o,
input logic count_enable_i,
input logic count_clr_i,
output logic count_ov_o
);
localparam OFFSET_WIDTH = $clog2(CACHE_LINE);
logic [FETCH_ADDR_WIDTH-1:0] fetch_addr_Q;
logic fetch_req_Q;
logic save_pipe_status;
logic clear_pipe;
logic enable_pipe;
logic save_victim_way;
logic [SCM_TAG_ADDR_WIDTH-1:0] counter_FLUSH_NS, counter_FLUSH_CS;
logic [OFFSET_WIDTH-1:0 ] refill_cnt_d, refill_cnt_q;
logic [NB_WAYS-1:0 ] DATA_CS, DATA_CS_d;
logic [NB_WAYS-1:0 ] TAG_CS, TAG_CS_d;
logic [NB_WAYS-1:0 ] TAG_WE, TAG_WE_d;
logic [SCM_TAG_WIDTH-1:0] TAG_WDATA, TAG_WDATA_d;
logic DATA_WE, DATA_WE_d;
logic [SCM_DATA_WIDTH-1:0] DATA_WDATA, DATA_WDATA_d;
logic is_same_block;
logic in_correcting, in_correcting_d;
logic fetch_we_q;
logic [SCM_DATA_WIDTH-1:0] fetch_wdata_q;
logic [NB_WAYS-1:0] way_match;
logic [NB_WAYS-1:0] way_valid;
logic [NB_WAYS-1:0] way_match_bin;
logic [NB_WAYS-1:0] way_valid_Q;
logic [$clog2(NB_WAYS)-1:0] random_way;
logic [$clog2(NB_WAYS)-1:0] first_available_way;
logic [$clog2(NB_WAYS)-1:0] HIT_WAY;
logic [$clog2(NB_WAYS)-1:0] victim_d, victim_q;
logic pending_trans_dis_cache;
logic [FETCH_DATA_WIDTH-1:0] axi_r_data_int;
logic [AXI_DATA-1:0] axi_r_data_i_delay;
// Wait two 64 bits to combine 128 data//
always_comb
begin
case(FETCH_DATA_WIDTH)
32: //##WEI##
begin
axi_r_data_int = axi_r_data_i;
end
64:
begin
axi_r_data_int = axi_r_data_i;
end
128:
begin
axi_r_data_int[127:64] = axi_r_data_i;
axi_r_data_int[63:0] = axi_r_data_i_delay;
end
endcase
end // always_comb
always_ff @(posedge clk, negedge rst_n)
begin
if(~rst_n)
axi_r_data_i_delay <= '0;
else if(axi_r_valid_i & axi_r_ready_o)
axi_r_data_i_delay <= axi_r_data_i;
end
enum logic [2:0] { DISABLED_ICACHE, WAIT_REFILL_DONE, OPERATIVE, REQ_REFILL, WRITE_BACK, WAIT_PENDING_TRANS, FLUSH_ICACHE, FLUSH_SET_ID } CS, NS;
int unsigned i,j,index;
logic update_lfsr;
//FSM
always_ff @(posedge clk, negedge rst_n)
begin
if(~rst_n)
CS <= DISABLED_ICACHE;
else
CS <= NS;
end
//Fetch
always_ff @(posedge clk, negedge rst_n)
begin
if(~rst_n)
begin
fetch_addr_Q <= '0;
fetch_req_Q <= 1'b0;
fetch_we_q <= 0;
fetch_wdata_q <= 'b0;
end
else if(enable_pipe)
begin
fetch_req_Q <= 1'b1;
fetch_addr_Q <= fetch_addr_i;
fetch_we_q <= fetch_we_i;
fetch_wdata_q <= fetch_wdata_i;
end
else if(clear_pipe)
begin
fetch_req_Q <= '0;
fetch_we_q <= 0;
end
end
always_ff @(posedge clk, negedge rst_n)
begin
if(~rst_n)
way_valid_Q <= '0;
else if(save_pipe_status)
way_valid_Q <= way_valid;
end
always_ff @(posedge clk, negedge rst_n)
begin
if(~rst_n)
victim_q <= '0;
else if(save_victim_way)
victim_q <= victim_d;
end
always_ff @(posedge clk, negedge rst_n)
begin
if(~rst_n)
pending_trans_dis_cache <= '0;
//Use this code to be sure thhat there is not apending transaction when enable cache request is asserted
else if( (CS == DISABLED_ICACHE ) || (CS == WAIT_PENDING_TRANS))
begin
case({(axi_ar_valid_o & axi_ar_ready_i), (axi_r_last_i & axi_r_valid_i & axi_r_ready_o)})
2'b00: begin pending_trans_dis_cache <= pending_trans_dis_cache; end
2'b10: begin pending_trans_dis_cache <= 1'b1; end
2'b01: begin pending_trans_dis_cache <= 1'b0; end
2'b11: begin pending_trans_dis_cache <= 1'b1; end
endcase // {(axi_ar_valid_o & axi_ar_ready_i), (axi_r_last_i & axi_r_valid_i & axi_r_ready_o)}
end
else
pending_trans_dis_cache <= 1'b0;
end
always_ff @(posedge clk, negedge rst_n)
begin
if(~rst_n)
counter_FLUSH_CS <= '0;
else
counter_FLUSH_CS <= counter_FLUSH_NS;
end
always_ff @(posedge clk, negedge rst_n)
begin
if(~rst_n)
begin
ctrl_hit_count_icache_o <= '0;
ctrl_trans_count_icache_o <= '0;
ctrl_miss_count_icache_o <= '0;
end
else if(ctrl_clear_regs_icache_i)
begin
ctrl_hit_count_icache_o <= '0;
ctrl_trans_count_icache_o <= '0;
ctrl_miss_count_icache_o <= '0;
end
else if(ctrl_enable_regs_icache_i)
begin
// Count incoming transactions
if(fetch_req_i & fetch_gnt_o)
ctrl_trans_count_icache_o <= ctrl_trans_count_icache_o + 1'b1;
if( (CS == OPERATIVE) & fetch_req_Q & (|way_match))
ctrl_hit_count_icache_o <= ctrl_hit_count_icache_o + 1'b1;
if(axi_ar_valid_o & axi_ar_ready_i)
ctrl_miss_count_icache_o <= ctrl_miss_count_icache_o + 1'b1;
end
end
//DFF
always_ff @(posedge clk, negedge rst_n)
begin
if(~rst_n)
begin
refill_cnt_q <= 0;
DATA_CS <= 0;
TAG_CS <= 0;
in_correcting <= 0;
DATA_WE <= 0;
DATA_WDATA <= 0;
TAG_WE <= 0;
TAG_WDATA <= 0;
end
else // else
begin
refill_cnt_q <= refill_cnt_d ;
DATA_CS <= DATA_CS_d ;
TAG_CS <= TAG_CS_d ;
in_correcting <= in_correcting_d;
TAG_WE <= TAG_WE_d ;
DATA_WE <= DATA_WE_d ;
TAG_WDATA <= TAG_WDATA_d ;
DATA_WDATA <= DATA_WDATA_d ;
end
end
// --------------------- //
// TAG CHECK MULTI WAY //
// --------------------- //
genvar k;
generate
for(k=0; k<NB_WAYS; k++)
begin
assign way_match[k] = ((TAG_rdata_i[k][SCM_TAG_WIDTH-2] == 1'b1) && (TAG_rdata_i[k][SCM_TAG_WIDTH-3:0] == fetch_addr_Q[TAG_MSB:TAG_LSB]));
assign way_valid[k] = (TAG_rdata_i[k][SCM_TAG_WIDTH-2] == 1'b1);
end
endgenerate
//TAG RAM
always_comb
begin
if(CS == FLUSH_ICACHE)
begin
TAG_req_o = 4'b1111;
TAG_we_o = 1'b1;
TAG_addr_o = counter_FLUSH_CS;
TAG_wdata_o = '0;
end
else if(CS == FLUSH_SET_ID)
begin
TAG_req_o = '1;
TAG_we_o = 1'b1;
TAG_addr_o = flush_set_ID_addr_i[SET_ID_MSB:SET_ID_LSB];
TAG_wdata_o = '0;
end
else if((CS == OPERATIVE) & (~(bypass_icache_i | flush_icache_i | flush_set_ID_req_i ))) //No bypass
begin
//Read the DATA nd TAG
TAG_req_o = TAG_CS;
TAG_we_o = 1'b0;
TAG_addr_o = fetch_addr_Q[SET_ID_MSB:SET_ID_LSB];
TAG_wdata_o = {1'b1,fetch_addr_Q[TAG_MSB:TAG_LSB]};
end
else if(CS == WAIT_REFILL_DONE)
begin
TAG_req_o = '0;
TAG_req_o[victim_q] = (refill_cnt_q == 'b1) | (refill_cnt_q == 'b0);
TAG_we_o = refill_cnt_q == 'b0;
TAG_addr_o = fetch_addr_Q[SET_ID_MSB:SET_ID_LSB];
TAG_wdata_o = {fetch_we_q,1'b1,fetch_addr_Q[TAG_MSB:TAG_LSB]};
end
else begin
TAG_req_o = '0;
TAG_we_o = 1'b0;
TAG_addr_o = fetch_addr_i[SET_ID_MSB:SET_ID_LSB];
TAG_wdata_o = {1'b1,fetch_addr_Q[TAG_MSB:TAG_LSB]};
end
end
//DATA
always_comb
begin
if((CS == OPERATIVE) &(~(bypass_icache_i | flush_icache_i | flush_set_ID_req_i ))) //No bypass
begin
DATA_req_o = DATA_CS;
DATA_we_o = 1'b0;
DATA_wdata_o = axi_r_data_int;
DATA_addr_o = fetch_addr_Q[SET_ID_MSB:2];
end
else if(CS == WAIT_REFILL_DONE)
begin
DATA_req_o = '0;
DATA_req_o[victim_q] = axi_r_valid_i;
DATA_addr_o = {fetch_addr_Q[SET_ID_MSB:SET_ID_LSB], refill_cnt_q};
DATA_wdata_o = (fetch_we_q & (refill_cnt_q == fetch_addr_Q[SET_ID_LSB-1:2])) ? fetch_wdata_q : axi_r_data_int;
DATA_we_o = 1'b1;
end
else
begin
DATA_req_o = '0;
DATA_addr_o = fetch_addr_i[SET_ID_MSB:SET_ID_LSB];
DATA_wdata_o = axi_r_data_int;
DATA_we_o = 1'b0;
end
end
//Fetch
always_comb
begin
if(CS == DISABLED_ICACHE)
begin
fetch_rdata_o = axi_r_data_int;
fetch_rvalid_o = axi_r_valid_i & axi_r_last_i; // Must a single beat transaction
if(bypass_icache_i == 1'b1)
fetch_gnt_o = axi_ar_ready_i & fetch_req_i;
else
fetch_gnt_o = 1'b0;
end
else if(CS == WAIT_PENDING_TRANS)
begin
fetch_rdata_o = axi_r_data_int;
fetch_rvalid_o = axi_r_valid_i & axi_r_last_i; // Must a single beat transaction
fetch_gnt_o = 1'b0;
end
else if(CS == OPERATIVE)
begin
if((bypass_icache_i | flush_icache_i | flush_set_ID_req_i ) & fetch_req_Q & (|way_match))
fetch_rvalid_o = 1'b1;
else if(fetch_req_Q & (|way_match))
if(DATA_error_i[HIT_WAY])
fetch_rvalid_o = 1'b0;
else
fetch_rvalid_o = 1'b1;
else
fetch_rvalid_o = 1'b0;
fetch_gnt_o = fetch_req_i & ~(bypass_icache_i | flush_icache_i | flush_set_ID_req_i );
fetch_rdata_o = DATA_rdata_i[HIT_WAY];
end
else if(CS == WAIT_REFILL_DONE)
begin
fetch_gnt_o = 1'b0;
fetch_rdata_o = axi_r_data_int;
fetch_rvalid_o = axi_r_valid_i & (refill_cnt_q == fetch_addr_Q[SET_ID_LSB-1:2]);
end
else
begin
fetch_gnt_o = 1'b0;
fetch_rvalid_o = 1'b0;
fetch_rdata_o = axi_r_data_int; //FIXME ok for AXI 64 and 32bit INSTR
end
end
always_comb
begin
if(CS == OPERATIVE)
DATA_need_correct_o = way_match;
else
DATA_need_correct_o = '0;
end
always_comb
begin
if(CS == DISABLED_ICACHE)
flush_set_ID_ack_o = 1'b1;
else if(CS == WAIT_PENDING_TRANS)
flush_set_ID_ack_o = 1'b1;
else if(CS == FLUSH_ICACHE)
flush_set_ID_ack_o = 1'b1;
else if(CS == FLUSH_SET_ID)
flush_set_ID_ack_o = 1'b1;
else if(CS == OPERATIVE)
flush_set_ID_ack_o = 1'b0;
else if(CS == REQ_REFILL)
flush_set_ID_ack_o = 1'b0;
else if(CS == WAIT_REFILL_DONE)
flush_set_ID_ack_o = 1'b0;
else
flush_set_ID_ack_o = 1'b0;
end
always_comb
begin
case(CS)
DISABLED_ICACHE:
begin
if(bypass_icache_i == 1'b1)
NS = DISABLED_ICACHE;
else
NS = WAIT_PENDING_TRANS;
end
WAIT_PENDING_TRANS:
begin
if(pending_trans_dis_cache == 1'b0)
NS = FLUSH_ICACHE; // Flushing is made in the central controller
else
NS = WAIT_PENDING_TRANS;
end
FLUSH_ICACHE:
begin
if(counter_FLUSH_CS < 2**SCM_TAG_ADDR_WIDTH-1)
NS = FLUSH_ICACHE;
else
NS = OPERATIVE;
end
FLUSH_SET_ID:
begin
NS = OPERATIVE;
end
OPERATIVE:
begin
if((bypass_icache_i | flush_icache_i | flush_set_ID_req_i ))
begin
if(fetch_req_Q)
begin
if(|way_match)
begin
if(bypass_icache_i)
NS = DISABLED_ICACHE;
else if (flush_icache_i)
NS = FLUSH_ICACHE;
else
NS = FLUSH_SET_ID;
end
else
NS = REQ_REFILL;
end
else //~if(fetch_req_Q == 1'b1)
begin
if(bypass_icache_i)
NS = DISABLED_ICACHE;
else if (flush_icache_i)
NS = FLUSH_ICACHE;
else
NS = FLUSH_SET_ID;
end
end
else // NO Bypass request !! force on this case!!
begin
if(fetch_req_Q)
begin
if(|way_match)
NS = OPERATIVE;
else
NS = REQ_REFILL;
end
else //~fetch_req_Q
NS = OPERATIVE;
end
end
REQ_REFILL:
begin
if(TAG_rdata_i[victim_d][SCM_TAG_WIDTH-1] & axi_aw_ready_i)
NS = WRITE_BACK;
else if(axi_ar_ready_i)
NS = WAIT_REFILL_DONE;
else
NS = REQ_REFILL;
end
WRITE_BACK:
begin
if((refill_cnt_q == '1) & axi_ar_ready_i)
NS = WAIT_REFILL_DONE;
else
NS = WRITE_BACK;
end
WAIT_REFILL_DONE:
begin
if(axi_r_valid_i & axi_r_last_i)
begin
//enable_pipe = fetch_req_i;
//clear_pipe = ~fetch_req_i;
NS = OPERATIVE;
end
else
begin
NS = WAIT_REFILL_DONE;
end
end
default:
begin
NS = DISABLED_ICACHE;
end
endcase
end
always_comb
begin
if(CS == DISABLED_ICACHE)
axi_ar_len_o = 1; // Single beat trans
else
axi_ar_len_o = (CACHE_LINE*FETCH_DATA_WIDTH)/AXI_DATA-1;
end
always_comb
begin
if(CS == REQ_REFILL)
begin
if(way_valid_Q == '1) // all the lines are valid, invalidate one random line
begin
victim_d = random_way;
update_lfsr = 1'b1;
end
else
begin
victim_d = first_available_way;
update_lfsr = 1'b0;
end
end
else begin
victim_d = '0;
update_lfsr = 1'b0;
end
end
always_comb
begin
if(CS == DISABLED_ICACHE)
counter_FLUSH_NS = '0;
else if(CS == FLUSH_ICACHE)
if(counter_FLUSH_CS < 2**SCM_TAG_ADDR_WIDTH-1)
counter_FLUSH_NS = counter_FLUSH_CS + 1'b1;
else
counter_FLUSH_NS = '0;
else
counter_FLUSH_NS = counter_FLUSH_CS;
end
always_comb
begin
refill_cnt_d = refill_cnt_q;
if(CS == WAIT_REFILL_DONE)
begin
if(axi_r_valid_i) begin
if(axi_r_last_i)
refill_cnt_d = 0;
else
refill_cnt_d = refill_cnt_q + 1'b1;
end
end
else
refill_cnt_d = refill_cnt_q;
end
assign is_same_block = (fetch_addr_i[FETCH_ADDR_WIDTH-1:SET_ID_LSB] ==
fetch_addr_Q[FETCH_ADDR_WIDTH-1:SET_ID_LSB] );
assign save_victim_way = (CS == REQ_REFILL) ;
always_comb
begin
save_pipe_status = 1'b0;
if(CS == OPERATIVE)
begin
if((bypass_icache_i | flush_icache_i | flush_set_ID_req_i ))
begin
if(fetch_req_Q)
begin
if(~(|way_match))
save_pipe_status = 1'b1;
end
end
else // NO Bypass request !!
begin
if(fetch_req_Q)
begin
if(~(|way_match))
save_pipe_status = 1'b1;
end
end
end
end
always_comb
begin
//enable_pipe = 1'b0;
if(CS == OPERATIVE)
begin
if(~(bypass_icache_i | flush_icache_i | flush_set_ID_req_i ))
begin
if(fetch_req_Q &(|way_match)&DATA_error_i[HIT_WAY])
enable_pipe = 0;
else if(fetch_req_Q &(~(|way_match)))
enable_pipe = 0;
else
enable_pipe = fetch_req_i;
end
else
enable_pipe = 1'b0;
end
else //if(CS == REQ_REFILL)
enable_pipe = 1'b0;
end
always_comb
begin
if(CS == DISABLED_ICACHE)
clear_pipe = 1'b1;
else if(CS == WAIT_PENDING_TRANS)
clear_pipe = 1'b1;
else if(CS == OPERATIVE)
begin
if((bypass_icache_i | flush_icache_i | flush_set_ID_req_i )) begin
//clear_pipe = 1'b0;
if(fetch_req_Q & (|way_match) &(fetch_req_i == 1'b0))
clear_pipe = 1'b1;
else if(~fetch_req_Q)
clear_pipe = 1'b1;
else
clear_pipe = 1'b0;
end
else
begin
if(fetch_req_Q & (|way_match) & (~DATA_error_i[HIT_WAY]))
clear_pipe = ~fetch_req_i;
else
clear_pipe = 1'b0;
end
end
else if(CS == WAIT_REFILL_DONE)
clear_pipe = axi_r_valid_i & (refill_cnt_q == fetch_addr_Q[SET_ID_LSB-1:2]);
else
clear_pipe = 1'b0;
end
always_comb
begin
if((CS == OPERATIVE) & (~(bypass_icache_i | flush_icache_i | flush_set_ID_req_i )))
begin
if(fetch_req_Q & (|way_match) & fetch_we_q & (~DATA_WE))
begin
TAG_CS_d = way_match & ~{NB_WAYS{TAG_rdata_i[HIT_WAY][SCM_TAG_WIDTH-1]}};
TAG_WE_d = way_match & ~{NB_WAYS{TAG_rdata_i[HIT_WAY][SCM_TAG_WIDTH-1]}};
DATA_CS_d = way_match;
DATA_WE_d = |way_match;
end
else if(fetch_req_Q & (|way_match) & (~fetch_we_q) & DATA_error_i[HIT_WAY])
begin
DATA_WE_d = 'b0;
TAG_WE_d = 'b0;
DATA_CS_d = way_match;
TAG_CS_d = 'b0;
end
else if(fetch_req_i)
begin
if(is_same_block)
begin
if(fetch_we_i) begin
DATA_WE_d = 1'b1;
TAG_WE_d = way_match & ~{NB_WAYS{TAG_rdata_i[HIT_WAY][SCM_TAG_WIDTH-1]}};
DATA_CS_d = way_match;
TAG_CS_d = way_match & ~{NB_WAYS{TAG_rdata_i[HIT_WAY][SCM_TAG_WIDTH-1]}};
end
else begin
DATA_WE_d = 'b0;
TAG_WE_d = 'b0;
DATA_CS_d = way_match;
TAG_CS_d = 'b0;
end
end
else //not the same block
begin
if(fetch_we_i) begin
DATA_WE_d = 'b0;
TAG_WE_d = 'b0;
DATA_CS_d = 'b0;
TAG_CS_d = 4'b1111;
end
else begin
DATA_WE_d = 'b0;
TAG_WE_d = 'b0;
TAG_CS_d = 4'b1111;
DATA_CS_d = 4'b1111;
end
end
end //~if(fetch_req_i)
else
begin
DATA_WE_d = 'b0;
TAG_WE_d = 'b0;
DATA_CS_d = 'b0;
TAG_CS_d = 'b0;
end
end
else
begin
DATA_WE_d = 'b0;
TAG_WE_d = 'b0;
DATA_CS_d = 'b0;
TAG_CS_d = 'b0;
end
end
always_comb
begin
axi_ar_valid_o = 1'b0;
axi_r_ready_o = 1'b1;
axi_ar_addr_o = fetch_addr_i;
axi_aw_addr_o = 0;
axi_aw_valid_o = 0;
axi_w_data_o = 0;
axi_w_valid_o = 0;
axi_w_last_o = 0;
if(CS == DISABLED_ICACHE)
begin
if(bypass_icache_i == 1'b1) // Already Bypassed
begin
axi_ar_valid_o = fetch_req_i;
axi_ar_addr_o = fetch_addr_i;
end
else
begin // Enable ICache
axi_ar_valid_o = 1'b0;
end
end
else if (CS == WAIT_PENDING_TRANS)
axi_ar_valid_o = 1'b0;
else if (CS == REQ_REFILL)
begin
if(TAG_rdata_i[victim_d][SCM_TAG_WIDTH-1]) begin
axi_aw_valid_o = 1;
axi_aw_addr_o = {TAG_rdata_i[victim_d][SCM_TAG_WIDTH-3:0],fetch_addr_Q[SET_ID_MSB:SET_ID_LSB],5'b0};
end
else begin
axi_ar_valid_o = 1'b1;
axi_ar_addr_o = fetch_addr_Q;
end
end
else if (CS == WRITE_BACK)
begin
axi_w_data_o = DATA_rdata_i[victim_q];
axi_w_valid_o = ~DATA_error_i[victim_q];
if(refill_cnt_q == '1)
begin
axi_w_last_o = axi_w_ready_i ? 1 : 0;
axi_ar_valid_o = 1;
axi_ar_addr_o = fetch_addr_Q;
end
end
end
always_comb
begin
if(CS == OPERATIVE)
begin
if(~(bypass_icache_i | flush_icache_i | flush_set_ID_req_i ))
begin
if(fetch_req_Q &(|way_match)& DATA_error_i[HIT_WAY])
in_correcting_d = 1 ;
else
in_correcting_d = 0 ;
end
else
in_correcting_d = 0 ;
end
else
in_correcting_d = 0 ;
end
//always_comb
//begin
// if((CS == OPERATIVE) & (~(bypass_icache_i | flush_icache_i | flush_set_ID_req_i )))
// begin
// TAG_wdata_o = {1'b1, 1'b1, TAG_rdata_i[HIT_WAY][SCM_TAG_WIDTH-3:0]};
// DATA_wdata_o = fetch_wdata_q;
// end
always_comb
begin
if(CS == DISABLED_ICACHE)
begin
cache_is_bypassed_o = 1'b1;
cache_is_flushed_o = 1'b1;
end
else if(CS == WAIT_PENDING_TRANS)
begin
cache_is_bypassed_o = 1'b1;
cache_is_flushed_o = 1'b1;
end
else if(CS == FLUSH_ICACHE)
begin
cache_is_flushed_o = (~(counter_FLUSH_CS < 2**SCM_TAG_ADDR_WIDTH-1));
cache_is_bypassed_o = 1'b0;
end //~FLUSH_ICACHE
else begin
cache_is_bypassed_o = 1'b0;
cache_is_flushed_o = 1'b0;
end
end
generate
if(NB_WAYS == 1)
begin : DIRECT_MAPPED
assign random_way = 1'b0;
end
else
begin : MULTI_WAY_SET_ASSOCIATIVE
LFSR_8bit
i_LFSR_Way_Repl
(
.data_o ( random_way ),
.enable_i ( update_lfsr ),
.clk ( clk ),
.rst_n ( rst_n )
);
end
endgenerate
logic error_q;
always_ff @(posedge clk, negedge rst_n)
begin
if(~rst_n)
begin
ref_count_o <= 0;
err_count_o <= 0;
cycle_count_o <= 0;
count_ov_o <= 0;
error_q <= 0;
end
else begin
error_q <= DATA_error_i[HIT_WAY];
if(count_clr_i)
begin
ref_count_o <= 0;
err_count_o <= 0;
cycle_count_o <= 0;
count_ov_o <= 0;
end
else if((CS == OPERATIVE) & (|way_match) & (~fetch_we_q) & count_enable_i)
begin
if(ref_count_o != 20'h00FFF)
begin
if(fetch_rvalid_o) begin
ref_count_o <= ref_count_o + 1'b1;
end
if(~error_q & DATA_error_i[HIT_WAY]) begin
err_count_o <= err_count_o + 1'b1;
end
if(DATA_CS[HIT_WAY]) begin
cycle_count_o <= cycle_count_o + 1'b1;
end
end
else begin
count_ov_o <= 1'b1;
end
end
end
end
always_comb
begin
first_available_way = 0;
for(index=0;index<NB_WAYS;index++)
begin
if(way_valid_Q[index]==0)
first_available_way=index;
end
HIT_WAY = 0;
for(index=0;index<NB_WAYS;index++)
begin
if(way_match[index]==1)
HIT_WAY=index;
end
end
generate
if (NB_WAYS != 1)
begin
onehot_to_bin #( .ONEHOT_WIDTH(NB_WAYS) ) WAY_MATCH_BIN (.onehot(way_match), .bin(way_match_bin[ $clog2(NB_WAYS)-1:0]) );
assign way_match_bin[NB_WAYS-1:$clog2(NB_WAYS)] = 0;
end
else
begin
assign way_match_bin = '0;
end
endgenerate
endmodule // icache_top