【随感杂想】Cache优化

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


   // 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 [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     = $clog2(SCM_DATA_WIDTH*CACHE_LINE)-3;//8-3=5


   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 [$clog2(CACHE_LINE)-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 is_same_block;
   logic in_correcting, in_correcting_d;

   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]            victim_d, victim_q;

   logic [$clog2(NB_WAYS)-1:0]            HIT_WAY;
   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)
    begin
       axi_r_data_i_delay <= '0;
    end
    else
    begin
        if(axi_r_valid_i & axi_r_ready_o)
            axi_r_data_i_delay <= axi_r_data_i;
    end
end

enum logic [2:0] { DISABLED_ICACHE,WAIT_REFILL_DONE, OPERATIVE, REQ_REFILL , 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   <= '1;
        fetch_req_Q    <= 1'b0;
    end
    else if(enable_pipe)
    begin
        fetch_req_Q    <= 1'b1;
        fetch_addr_Q   <= fetch_addr_i;
    end
    else  if(clear_pipe)
    begin
        fetch_req_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;
    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;
   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-1] == 1'b1) && (TAG_rdata_i[k][SCM_TAG_WIDTH-2:0] == fetch_addr_Q[TAG_MSB:TAG_LSB]));
      assign way_valid[k]  = (TAG_rdata_i[k][SCM_TAG_WIDTH-1] == 1'b1);
   end
endgenerate

//TAG RAM
always_comb
begin
    if(CS == FLUSH_ICACHE)
    begin
        TAG_req_o   = '1;
        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    = {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    = 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
    if(CS == DISABLED_ICACHE)
        if(bypass_icache_i == 1'b1)
            NS = DISABLED_ICACHE;
        else
            NS = WAIT_PENDING_TRANS;
            
    else if(CS == WAIT_PENDING_TRANS)            
        if(pending_trans_dis_cache == 1'b0)
            NS = FLUSH_ICACHE; // Flushing is made in the central controller
        else
            NS = WAIT_PENDING_TRANS;
            
    else if(CS == FLUSH_ICACHE)  
        if(counter_FLUSH_CS < 2**SCM_TAG_ADDR_WIDTH-1)
            NS = FLUSH_ICACHE;
        else
            NS = OPERATIVE;

    else if(CS == FLUSH_SET_ID) 
            NS = OPERATIVE; 
            
    else 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)
                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 !!   
        begin        
            if(fetch_req_Q)
            begin
                if(|way_match)
                    NS = OPERATIVE;
                else
                    NS = REQ_REFILL;
            end
            else //~fetch_req_Q
                NS = OPERATIVE;
        end
    end    
    else if(CS == REQ_REFILL)     
    begin
         if(axi_ar_ready_i)
           NS = WAIT_REFILL_DONE;
        else
           NS = REQ_REFILL;
    end            
    else if(CS == 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
    else
        NS = DISABLED_ICACHE;
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;
      enable_pipe             = 1'b0;
      clear_pipe              = 1'b0;
      DATA_CS_d = 'b0;
      TAG_CS_d = 'b0;

      case(CS)

         DISABLED_ICACHE:
         begin
            clear_pipe          = 1'b1;
         end

         WAIT_PENDING_TRANS:
         begin
            clear_pipe            = 1'b1;
         end

         OPERATIVE:
         begin
            if(bypass_icache_i | flush_icache_i | flush_set_ID_req_i ) // first check if the previous fetch has a miss or HIT
            begin
               if(fetch_req_Q)
               begin
                   if(|way_match)
                   begin
                      if(fetch_req_i == 1'b0)
                         clear_pipe = 1'b1;
                   end
                   else
                   begin 
                      // asks for the last refill, then goes into DISABLED state
                      save_pipe_status = 1'b1;
                   end
               end //~if(fetch_req_Q == 1'b1)
               else
               begin
                  clear_pipe = 1'b1;
               end//~else(fetch_req_Q)
            end
            else // NO Bypass request
            begin
              enable_pipe          = fetch_req_i;
              
              if (fetch_req_i) begin
                if(is_same_block) begin
                  DATA_CS_d = way_match;
                  TAG_CS_d = 'b0;
                end 
                else begin
                  DATA_CS_d = 4'b1111;
                  TAG_CS_d = 4'b1111;
                end 
              end 
               if(fetch_req_Q)
               begin
                   if(|way_match)
                   begin
                      if(DATA_error_i[HIT_WAY]) begin
                        DATA_CS_d = way_match;
                        TAG_CS_d = 'b0;
                        enable_pipe = 0;
                      end else begin
                        clear_pipe = ~fetch_req_i;
                      end 
                   end
                   else
                   begin
                      save_pipe_status = 1'b1;
                      enable_pipe      = 1'b0;
                   end
               end
            end

         end

         REQ_REFILL:
         begin
            enable_pipe      = 1'b0;
         end

         WAIT_REFILL_DONE:
         begin
            clear_pipe = axi_r_valid_i & (refill_cnt_q == fetch_addr_Q[SET_ID_LSB-1:2]);
         end // case: WAIT_REFILL_DONE
      endcase // CS
   end


*/

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
            enable_pipe          = fetch_req_i;
            if(fetch_req_Q)
            begin
                if(|way_match)
                begin
                    if(DATA_error_i[HIT_WAY])
                        enable_pipe = 0;
                end
                else
                    enable_pipe      = 1'b0;
            end
        end
    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) 
                if(|way_match) begin
                    if(fetch_req_i == 1'b0)
                        clear_pipe = 1'b1;
                end
            else
                clear_pipe = 1'b1;
        end
        else
        begin
            clear_pipe              = 1'b0;
            if(fetch_req_Q)
            begin
                if(|way_match) begin
                    if(~DATA_error_i[HIT_WAY])
                        clear_pipe =  ~fetch_req_i;
                end
            end
        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

    DATA_CS_d = 'b0;
    TAG_CS_d = 'b0;
      
    if(CS == OPERATIVE)         
        if(~(bypass_icache_i | flush_icache_i | flush_set_ID_req_i ))
            if (fetch_req_i) begin
                if(is_same_block) begin
                  DATA_CS_d = way_match;
                  TAG_CS_d = 'b0;
                end 
                else begin
                  DATA_CS_d = 4'b1111;
                  TAG_CS_d = 4'b1111;
                end 
            end
            else if(fetch_req_Q)
                begin
                   if(|way_match)
                        if(DATA_error_i[HIT_WAY]) begin
                            DATA_CS_d = way_match;
                            TAG_CS_d = 'b0;
                        end
                end
end


always_comb
begin
    axi_ar_valid_o            = 1'b0;
    axi_r_ready_o             = 1'b1;
    axi_ar_addr_o             = fetch_addr_i;

    cache_is_bypassed_o     = 1'b0;
    cache_is_flushed_o      = 1'b0;
    
    in_correcting_d = 0;

    case(CS)
       DISABLED_ICACHE:
       begin
          cache_is_bypassed_o = 1'b1;
          cache_is_flushed_o  = 1'b1;
  
          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

       WAIT_PENDING_TRANS:
       begin
          cache_is_bypassed_o   = 1'b1;
          cache_is_flushed_o    = 1'b1;
          axi_ar_valid_o        = 1'b0;
       end

       FLUSH_ICACHE:
       begin
          if(~(counter_FLUSH_CS < 2**SCM_TAG_ADDR_WIDTH-1))
             cache_is_flushed_o  = 1'b1;
       end //~FLUSH_ICACHE

       OPERATIVE:
       begin
          cache_is_bypassed_o  = 1'b0;
          cache_is_flushed_o   = 1'b0;

          if(~(bypass_icache_i | flush_icache_i | flush_set_ID_req_i )) // first check if the previous fetch has a miss or HIT
          begin
             if(fetch_req_Q)
             begin
                 if(|way_match)
                 begin : HIT
                    if(DATA_error_i[HIT_WAY])
                      in_correcting_d = 1;
                 end
             end
          end
       end

      REQ_REFILL:
       begin
          cache_is_bypassed_o  = 1'b0;
          cache_is_flushed_o   = 1'b0;

          axi_ar_valid_o   = 1'b1;
          axi_ar_addr_o    = fetch_addr_Q;

       end

       WAIT_REFILL_DONE:
       begin
          cache_is_bypassed_o  = 1'b0;
          cache_is_flushed_o   = 1'b0;
       end // case: WAIT_REFILL_DONE
    
       //default: ;
    endcase // CS
end

generate
   if(NB_WAYS == 1)
   begin : DIRECT_MAPPED
      assign random_way = 1'b1;
   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) & 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


module LFSR_8bit(
  output logic [1:0] data_o,
  input  logic enable_i,
  input  logic clk, 
  input  logic rst_n
);
logic q1,q2,q3,q4,q5,q6,q7,q8;
logic d1,d2,d3,d4,d5,d6,d7,d8;

always_ff @(posedge clk, negedge rst_n) begin
  if(~rst_n) begin
    q1 <= 1;
    q2 <= 1;
    q3 <= 1;
    q4 <= 1;
    q5 <= 1;
    q6 <= 1;
    q7 <= 1;
    q8 <= 1;
  end 
  else begin
    if(enable_i) begin
      q1 <= d1;
      q2 <= d2;
      q3 <= d3;
      q4 <= d4;
      q5 <= d5;
      q6 <= d6;
      q7 <= d7;
      q8 <= d8;
    end
  end
end 
assign d1 = q2^q3^q4^q8;
assign d2 = q1;
assign d3 = q2;
assign d4 = q3;
assign d5 = q4;
assign d6 = q5;
assign d7 = q6;
assign d8 = q7;
assign data_o = {q7,q8};
endmodule

 

posted @ 2021-04-19 12:44  digital-world  阅读(73)  评论(0编辑  收藏  举报