dcache

// 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

  

posted @ 2021-04-20 19:21  digital-world  阅读(335)  评论(0编辑  收藏  举报