【随感杂想】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_bank_private.sv*/

module icache_bank_private
#(
   parameter FETCH_ADDR_WIDTH = 32,
   parameter FETCH_DATA_WIDTH = 32,

   parameter NB_WAYS          = 4,
   parameter CACHE_SIZE       = 4096, // in Byte
   parameter CACHE_LINE       = 8,    // in word of [FETCH_DATA_WIDTH]

   parameter USE_REDUCED_TAG  = "FALSE",
   parameter TAG_BITS         = 9,

   parameter AXI_ID           = 10,
   parameter AXI_ADDR         = 32,
   parameter AXI_USER         = 1,
   parameter AXI_DATA         = 32
)
(
   input logic                                           clk,
   input logic                                           rst_n,
   input logic                                           test_en_i,

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

   //AXI read address bus -------------------------------------------
   output  logic [AXI_ID-1:0]                            axi_master_arid_o,
   output  logic [AXI_ADDR-1:0]                          axi_master_araddr_o,
   output  logic [ 7:0]                                  axi_master_arlen_o,    //burst length - 1 to 16
   output  logic [ 2:0]                                  axi_master_arsize_o,   //size of each transfer in burst
   output  logic [ 1:0]                                  axi_master_arburst_o,  //for bursts>1, accept only incr burst=01
   output  logic                                         axi_master_arlock_o,   //only normal access supported axs_awlock=00
   output  logic [ 3:0]                                  axi_master_arcache_o,
   output  logic [ 2:0]                                  axi_master_arprot_o,
   output  logic [ 3:0]                                  axi_master_arregion_o, //
   output  logic [ AXI_USER-1:0]                         axi_master_aruser_o,   //
   output  logic [ 3:0]                                  axi_master_arqos_o,    //
   output  logic                                         axi_master_arvalid_o,  //master addr valid
   input logic                                           axi_master_arready_i,  //slave ready to accept
   // ---------------------------------------------------------------


   //AXI BACKWARD read data bus ----------------------------------------------
   input   logic [AXI_ID-1:0]                            axi_master_rid_i,
   input   logic [AXI_DATA-1:0]                          axi_master_rdata_i,
   input   logic [1:0]                                   axi_master_rresp_i,
   input   logic                                         axi_master_rlast_i,    //last transfer in burst
   input   logic [AXI_USER-1:0]                          axi_master_ruser_i,
   input   logic                                         axi_master_rvalid_i,   //slave data valid
   output  logic                                         axi_master_rready_o,    //master ready to accept

   // NOT USED ----------------------------------------------
   output logic [AXI_ID-1:0]                             axi_master_awid_o,
   output logic [AXI_ADDR-1:0]                           axi_master_awaddr_o,
   output logic [ 7:0]                                   axi_master_awlen_o,
   output logic [ 2:0]                                   axi_master_awsize_o,
   output logic [ 1:0]                                   axi_master_awburst_o,
   output logic                                          axi_master_awlock_o,
   output logic [ 3:0]                                   axi_master_awcache_o,
   output logic [ 2:0]                                   axi_master_awprot_o,
   output logic [ 3:0]                                   axi_master_awregion_o,
   output logic [ AXI_USER-1:0]                          axi_master_awuser_o,
   output logic [ 3:0]                                   axi_master_awqos_o,
   output logic                                          axi_master_awvalid_o,
   input  logic                                          axi_master_awready_i,

   // NOT USED ----------------------------------------------
   output logic  [AXI_DATA-1:0]                          axi_master_wdata_o,
   output logic  [AXI_DATA/8-1:0]                        axi_master_wstrb_o,
   output logic                                          axi_master_wlast_o,
   output logic  [ AXI_USER-1:0]                         axi_master_wuser_o,
   output logic                                          axi_master_wvalid_o,
   input  logic                                          axi_master_wready_i,
   // ---------------------------------------------------------------

   // NOT USED ----------------------------------------------
   input  logic  [AXI_ID-1:0]                            axi_master_bid_i,
   input  logic  [ 1:0]                                  axi_master_bresp_i,
   input  logic  [ AXI_USER-1:0]                         axi_master_buser_i,
   input  logic                                          axi_master_bvalid_i,
   output logic                                          axi_master_bready_o,
   // ---------------------------------------------------------------

   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,

   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,


   input  logic               [31:0] cache_config_i,

   input  logic                      cache_stat_start_i,
   input  logic                      cache_stat_clr_i,
   output logic                      cache_stat_ov_o,

   output logic               [31:0] cache_ref_cnt_o,
   output logic               [31:0] cache_err_cnt_o,
   output logic               [31:0] cache_cycle_cnt_o
);


   localparam OFFSET             = $clog2(FETCH_DATA_WIDTH)-3;//5-3=2
   localparam WAY_SIZE           = CACHE_SIZE/NB_WAYS;//4096/4=1024
   localparam SCM_NUM_ROWS       = WAY_SIZE/(CACHE_LINE*FETCH_DATA_WIDTH/8); // TAG 1024/(8*32/8) = 32
   localparam SCM_TAG_ADDR_WIDTH = (SCM_NUM_ROWS == 1 ) ? 1 : $clog2(SCM_NUM_ROWS);//log(32) = 5

   localparam LRU_BITS           = 2;
   localparam TAG_WIDTH          = (USE_REDUCED_TAG == "TRUE") ? (TAG_BITS + 1) : (FETCH_ADDR_WIDTH -  $clog2(SCM_NUM_ROWS) - $clog2(CACHE_LINE) - OFFSET + 1 + LRU_BITS);//32 - 5 - 3 - 2 + 1 = 23

   localparam RC_WIDTH           = 17;//32
   
   localparam DATA_WIDTH          = FETCH_DATA_WIDTH;//32
   localparam SCM_DATA_ADDR_WIDTH = $clog2(SCM_NUM_ROWS)+$clog2(CACHE_LINE);  //5 + 3 = 8 Because of 32 Access

   localparam SET_ID_LSB = $clog2(DATA_WIDTH*CACHE_LINE)-3;//8 - 3 = 5
   localparam SET_ID_MSB = (SCM_NUM_ROWS == 1) ? SET_ID_LSB :  SET_ID_LSB + SCM_TAG_ADDR_WIDTH - 1;//10
   localparam TAG_LSB    = (SCM_NUM_ROWS == 1) ? SET_ID_LSB :  SET_ID_MSB + 1;//11
   localparam TAG_MSB    = TAG_LSB + TAG_WIDTH - 2 ; //11 + 23 - 2 = 32   1 bit is count for valid

   logic [AXI_ID-1:0]                            axi_master_arid_int;
   logic [AXI_ADDR-1:0]                          axi_master_araddr_int;
   logic [ 7:0]                                  axi_master_arlen_int;
   logic [ 2:0]                                  axi_master_arsize_int;
   logic [ 1:0]                                  axi_master_arburst_int;
   logic                                         axi_master_arlock_int;
   logic [ 3:0]                                  axi_master_arcache_int;
   logic [ 2:0]                                  axi_master_arprot_int;
   logic [ 3:0]                                  axi_master_arregion_int;
   logic [ AXI_USER-1:0]                         axi_master_aruser_int;
   logic [ 3:0]                                  axi_master_arqos_int;
   logic                                         axi_master_arvalid_int;
   logic                                         axi_master_arready_int;


   logic [AXI_ID-1:0]                            axi_master_rid_int;
   logic [AXI_DATA-1:0]                          axi_master_rdata_int;
   logic [1:0]                                   axi_master_rresp_int;
   logic                                         axi_master_rlast_int;
   logic [AXI_USER-1:0]                          axi_master_ruser_int;
   logic                                         axi_master_rvalid_int;
   logic                                         axi_master_rready_int;

   logic clk_rbl;

   // interface with READ PORT --> SCM DATA
   logic [NB_WAYS-1:0]                           DATA_req_int;
   logic                                         DATA_we_int;
   logic [SCM_DATA_ADDR_WIDTH-1:0]               DATA_addr_int;
   logic [NB_WAYS-1:0][DATA_WIDTH-1:0]           DATA_rdata_int;
   logic [DATA_WIDTH-1:0]                        DATA_wdata_int;
   logic [NB_WAYS-1:0]                           DATA_error_int;
   logic [NB_WAYS-1:0]                           DATA_need_correct_int;

   // interface with READ PORT --> SCM TAG
   logic [NB_WAYS-1:0]                           TAG_req_int;
   logic                                         TAG_we_int;
   logic [SCM_TAG_ADDR_WIDTH-1:0]                TAG_addr_int;
   logic [NB_WAYS-1:0][TAG_WIDTH-1:0]            TAG_rdata_int;
   logic [TAG_WIDTH-1:0]                         TAG_wdata_int;


   logic [NB_WAYS-1:0]                           DATA_read_enable;
   logic [NB_WAYS-1:0]                           DATA_write_enable;

   logic [NB_WAYS-1:0]                           TAG_read_enable;
   logic [NB_WAYS-1:0]                           TAG_write_enable;

   // ██╗ ██████╗ █████╗  ██████╗██╗  ██╗███████╗         ██████╗████████╗██████╗ ██╗
   // ██║██╔════╝██╔══██╗██╔════╝██║  ██║██╔════╝        ██╔════╝╚══██╔══╝██╔══██╗██║
   // ██║██║     ███████║██║     ███████║█████╗          ██║        ██║   ██████╔╝██║
   // ██║██║     ██╔══██║██║     ██╔══██║██╔══╝          ██║        ██║   ██╔══██╗██║
   // ██║╚██████╗██║  ██║╚██████╗██║  ██║███████╗███████╗╚██████╗   ██║   ██║  ██║███████╗
   // ╚═╝ ╚═════╝╚═╝  ╚═╝ ╚═════╝╚═╝  ╚═╝╚══════╝╚══════╝ ╚═════╝   ╚═╝   ╚═╝  ╚═╝╚══════╝
   icache_controller_private
   #(
      .FETCH_ADDR_WIDTH      ( FETCH_ADDR_WIDTH     ),
      .FETCH_DATA_WIDTH      ( FETCH_DATA_WIDTH     ),

      .NB_WAYS               ( NB_WAYS              ),
      .CACHE_LINE            ( CACHE_LINE           ),

      .SCM_TAG_ADDR_WIDTH    ( SCM_TAG_ADDR_WIDTH   ),
      .SCM_DATA_ADDR_WIDTH   ( SCM_DATA_ADDR_WIDTH  ),
      .SCM_TAG_WIDTH         ( TAG_WIDTH            ),
      .SCM_DATA_WIDTH        ( DATA_WIDTH           ),
      .SCM_NUM_ROWS          ( SCM_NUM_ROWS         ),

      .SET_ID_LSB            ( SET_ID_LSB           ),
      .SET_ID_MSB            ( SET_ID_MSB           ),
      .TAG_LSB               ( TAG_LSB              ),
      .TAG_MSB               ( TAG_MSB              ),

      .AXI_ID                ( AXI_ID               ),
      .AXI_ADDR              ( AXI_ADDR             ),
      .AXI_USER              ( AXI_USER             ),
      .AXI_DATA              ( AXI_DATA             )
   )
   i_icache_controller_private
   (
      .clk                      ( clk                  ),
      .rst_n                    ( rst_n                ),
      .test_en_i                ( test_en_i            ),

      .bypass_icache_i          ( bypass_icache_i      ),
      .cache_is_bypassed_o      ( cache_is_bypassed_o  ),
      .flush_icache_i           ( flush_icache_i       ),
      .cache_is_flushed_o       ( cache_is_flushed_o   ),
      .flush_set_ID_req_i       ( flush_set_ID_req_i   ),
      .flush_set_ID_addr_i      ( flush_set_ID_addr_i  ),
      .flush_set_ID_ack_o       ( flush_set_ID_ack_o   ),

      // interface with processor
      .fetch_req_i              ( fetch_req_i          ),
      .fetch_addr_i             ( fetch_addr_i         ),
      .fetch_gnt_o              ( fetch_gnt_o          ),
      .fetch_rvalid_o           ( fetch_rvalid_o       ),
      .fetch_rdata_o            ( fetch_rdata_o        ),


      // interface with READ PORT --> SCM DATA
      .DATA_req_o               ( DATA_req_int         ),
      .DATA_we_o                ( DATA_we_int          ),
      .DATA_addr_o              ( DATA_addr_int        ),
      .DATA_rdata_i             ( DATA_rdata_int       ),
      .DATA_wdata_o             ( DATA_wdata_int       ),
      .DATA_error_i             ( DATA_error_int       ),
      .DATA_need_correct_o      ( DATA_need_correct_int),

      // interface with READ PORT --> SCM TAG
      .TAG_req_o                ( TAG_req_int          ),
      .TAG_addr_o               ( TAG_addr_int         ),
      .TAG_rdata_i              ( TAG_rdata_int        ),
      .TAG_wdata_o              ( TAG_wdata_int        ),
      .TAG_we_o                 ( TAG_we_int           ),

      // Interface to cache_controller_to_axi
      .axi_ar_valid_o           ( axi_master_arvalid_int ),
      .axi_ar_ready_i           ( axi_master_arready_int ),
      .axi_ar_addr_o            ( axi_master_araddr_int  ),
      .axi_ar_len_o             ( axi_master_arlen_int   ),

      .axi_r_valid_i            ( axi_master_rvalid_int  ),
      .axi_r_ready_o            ( axi_master_rready_int  ),
      .axi_r_data_i             ( axi_master_rdata_int   ),
      .axi_r_last_i             ( axi_master_rlast_int   ),

      .ctrl_hit_count_icache_o  (ctrl_hit_count_icache_o   ),
      .ctrl_trans_count_icache_o(ctrl_trans_count_icache_o ),
      .ctrl_miss_count_icache_o (ctrl_miss_count_icache_o  ),
      .ctrl_clear_regs_icache_i (ctrl_clear_regs_icache_i  ),
      .ctrl_enable_regs_icache_i(ctrl_enable_regs_icache_i ),

      .ref_count_o    ( cache_ref_cnt_o    ),
      .err_count_o    ( cache_err_cnt_o    ),
      .cycle_count_o  ( cache_cycle_cnt_o  ),
      .count_enable_i ( cache_stat_start_i ),
      .count_clr_i    ( cache_stat_clr_i   ),
      .count_ov_o     ( cache_stat_ov_o    )
   );

   rbl 
   #(.CK_PERIOD(0.19))
   rbl_i(
      .CLK_RBL(clk_rbl)
   );

      genvar i;
      generate

      // ████████╗ █████╗  ██████╗         ██████╗  █████╗ ███╗   ██╗██╗  ██╗
      // ╚══██╔══╝██╔══██╗██╔════╝         ██╔══██╗██╔══██╗████╗  ██║██║ ██╔╝
      //    ██║   ███████║██║  ███╗        ██████╔╝███████║██╔██╗ ██║█████╔╝
      //    ██║   ██╔══██║██║   ██║        ██╔══██╗██╔══██║██║╚██╗██║██╔═██╗
      //    ██║   ██║  ██║╚██████╔╝███████╗██████╔╝██║  ██║██║ ╚████║██║  ██╗
      //    ╚═╝   ╚═╝  ╚═╝ ╚═════╝ ╚══════╝╚═════╝ ╚═╝  ╚═╝╚═╝  ╚═══╝╚═╝  ╚═╝
      for(i=0; i<NB_WAYS; i++)
      begin : _TAG_WAY_
         assign TAG_read_enable[i]  = TAG_req_int[i];
         assign TAG_write_enable[i] = TAG_req_int[i] &  TAG_we_int;


         tag_ram 
         #(
            .TAG_WIDTH  ( TAG_WIDTH          ),
            .ADDR_WIDTH ( SCM_TAG_ADDR_WIDTH )
         ) tag_array
         (
            .clk     ( clk   ),
            .rst_n   ( rst_n ), 
            .en_i    ( TAG_read_enable[i]  ),
            .addr_i  ( TAG_addr_int       ), 
            .we_i    ( TAG_write_enable[i] ), 
            .wdata_i ( TAG_wdata_int       ),
            .rdata_o ( TAG_rdata_int[i]    ) 
         );
      end
      
      rc_ram #(
            .RC_WIDTH  (RC_WIDTH          ),
            .ADDR_WIDTH(SCM_TAG_ADDR_WIDTH),
            .INIT_FILE ("../testbench/rc0.dat")
         ) rc_array0
      
         (
            .clk     ( clk   ),
            .rst_n   ( rst_n ), 
            .en_i    ( TAG_read_enable[0] ),
            .addr_i  ( TAG_addr_int       ), 
            .we_i    ( 0                  ), 
            .wdata_i ( 0                  ),
            .rdata_o ( RC_rdata_int[0]    ) 
         );     
      
      rc_ram #(
            .RC_WIDTH  (RC_WIDTH          ),
            .ADDR_WIDTH(SCM_TAG_ADDR_WIDTH),
            .INIT_FILE("../testbench/rc1.dat")
         ) rc_array1
      
         (
            .clk     ( clk   ),
            .rst_n   ( rst_n ), 
            .en_i    ( TAG_read_enable[1] ),
            .addr_i  ( TAG_addr_int       ), 
            .we_i    ( 0                  ), 
            .wdata_i ( 0                  ),
            .rdata_o ( RC_rdata_int[1]    ) 
         ); 
         
      rc_ram #(
            .RC_WIDTH  (RC_WIDTH          ),
            .ADDR_WIDTH(SCM_TAG_ADDR_WIDTH),      
            .INIT_FILE("../testbench/rc2.dat")
         ) rc_array2
      
         (
            .clk     ( clk   ),
            .rst_n   ( rst_n ), 
            .en_i    ( TAG_read_enable[2] ),
            .addr_i  ( TAG_addr_int       ), 
            .we_i    ( 0                  ), 
            .wdata_i ( 0                  ),
            .rdata_o ( RC_rdata_int[2]    ) 
         ); 

      rc_ram #(
            .RC_WIDTH  (RC_WIDTH          ),
            .ADDR_WIDTH(SCM_TAG_ADDR_WIDTH),      
            .INIT_FILE("../testbench/rc3.dat")
         ) rc_array3
      
         (
            .clk     ( clk   ),
            .rst_n   ( rst_n ), 
            .en_i    ( TAG_read_enable[3] ),
            .addr_i  ( TAG_addr_int       ), 
            .we_i    ( 0                  ), 
            .wdata_i ( 0                  ),
            .rdata_o ( RC_rdata_int[3]    ) 
         );          
      // ██████╗  █████╗ ████████╗ █████╗         ██████╗  █████╗ ███╗   ██╗██╗  ██╗
      // ██╔══██╗██╔══██╗╚══██╔══╝██╔══██╗        ██╔══██╗██╔══██╗████╗  ██║██║ ██╔╝
      // ██║  ██║███████║   ██║   ███████║        ██████╔╝███████║██╔██╗ ██║█████╔╝
      // ██║  ██║██╔══██║   ██║   ██╔══██║        ██╔══██╗██╔══██║██║╚██╗██║██╔═██╗
      // ██████╔╝██║  ██║   ██║   ██║  ██║███████╗██████╔╝██║  ██║██║ ╚████║██║  ██╗
      // ╚═════╝ ╚═╝  ╚═╝   ╚═╝   ╚═╝  ╚═╝╚══════╝╚═════╝ ╚═╝  ╚═╝╚═╝  ╚═══╝╚═╝  ╚═╝


      for(i=0; i<NB_WAYS; i++)
      begin : _DATA_WAY_
         assign DATA_read_enable[i]  = DATA_req_int[i] ;
         assign DATA_write_enable[i] = DATA_req_int[i] & DATA_we_int;
      end
         ssram #(
            .TBL_FILE("../testbench/tbl0.dat")
         ) 
         data_array0(
            .SLEEP    ( 1'b0    ),
            .rst_n    ( rst_n   ),
            .CLK      ( clk     ),
            .CLK_G    ( 1'b0    ),
            .CLK_RBL  ( clk_rbl ),
            .MODE     ( DATA_need_correct_int[0]),
            .BOOST_EN ( 1'b0    ),
            .CEN      ( ~DATA_read_enable[0]  ),
            .WEN      ( ~DATA_write_enable[0] ),
            .FLAG     ( DATA_error_int[0]     ),
            .EN       ( cache_config_i        ),
            .BRS      ( DATA_addr_int         ),
            .WL_IN    ( 256'b0                ),
            .D        ( DATA_wdata_int        ),
            .Q        ( DATA_rdata_int[0]     ) 
         );
         ssram #(
            .TBL_FILE("../testbench/tbl1.dat")
         )
         data_array1(
            .SLEEP    ( 1'b0    ),
            .rst_n    ( rst_n   ),
            .CLK      ( clk     ),
            .CLK_G    ( 1'b0    ),
            .CLK_RBL  ( clk_rbl ),
            .MODE     ( DATA_need_correct_int[1]),
            .BOOST_EN ( 1'b0    ),
            .CEN      ( ~DATA_read_enable[1]  ),
            .WEN      ( ~DATA_write_enable[1] ),
            .FLAG     ( DATA_error_int[1]     ),
            .EN       ( cache_config_i        ),
            .BRS      ( DATA_addr_int         ),
            .WL_IN    ( 256'b0                ),
            .D        ( DATA_wdata_int        ),
            .Q        ( DATA_rdata_int[1]     ) 
         );
         ssram #(
            .TBL_FILE("../testbench/tbl2.dat")
         ) 
         data_array2(
            .SLEEP    ( 1'b0    ),
            .rst_n    ( rst_n   ),
            .CLK      ( clk     ),
            .CLK_G    ( 1'b0    ),
            .CLK_RBL  ( clk_rbl ),
            .MODE     ( DATA_need_correct_int[2]),
            .BOOST_EN ( 1'b0    ),
            .CEN      ( ~DATA_read_enable[2]  ),
            .WEN      ( ~DATA_write_enable[2] ),
            .FLAG     ( DATA_error_int[2]     ),
            .EN       ( cache_config_i        ),
            .BRS      ( DATA_addr_int         ),
            .WL_IN    ( 256'b0                ),
            .D        ( DATA_wdata_int        ),
            .Q        ( DATA_rdata_int[2]     ) 
         );
         ssram #(
            .TBL_FILE("../testbench/tbl3.dat")
         )
         data_array3(
            .SLEEP    ( 1'b0    ),
            .rst_n    ( rst_n   ),
            .CLK      ( clk     ),
            .CLK_G    ( 1'b0    ),
            .CLK_RBL  ( clk_rbl ),
            .MODE     ( DATA_need_correct_int[3]),
            .BOOST_EN ( 1'b0    ),
            .CEN      ( ~DATA_read_enable[3]  ),
            .WEN      ( ~DATA_write_enable[3] ),
            .FLAG     ( DATA_error_int[3]     ),
            .EN       ( cache_config_i        ),
            .BRS      ( DATA_addr_int         ),
            .WL_IN    ( 256'b0                ),
            .D        ( DATA_wdata_int        ),
            .Q        ( DATA_rdata_int[3]     ) 
         );
endgenerate



   assign axi_master_arid_int     = {AXI_ID{1'b0}};
   assign axi_master_arsize_int   = 3'b011;   //64 bits -> 8 bytes
   assign axi_master_arburst_int  = 2'b01;    //INCR
   assign axi_master_arlock_int   = 1'b0;
   assign axi_master_arcache_int  = 4'b0000;
   assign axi_master_arprot_int   = 3'b000;
   assign axi_master_arregion_int = 4'b0000;
   assign axi_master_aruser_int   = {AXI_USER{1'b0}};
   assign axi_master_arqos_int    = 4'b0000;

   assign axi_master_arvalid_o          = axi_master_arvalid_int;         
   assign axi_master_araddr_o           = axi_master_araddr_int;          
   assign axi_master_arprot_o           = axi_master_arprot_int;          
   assign axi_master_arregion_o         = axi_master_arregion_int;        
   assign axi_master_arlen_o            = axi_master_arlen_int;           
   assign axi_master_arsize_o           = axi_master_arsize_int;          
   assign axi_master_arburst_o          = axi_master_arburst_int;         
   assign axi_master_arlock_o           = axi_master_arlock_int;          
   assign axi_master_arcache_o          = axi_master_arcache_int;         
   assign axi_master_arqos_o            = axi_master_arqos_int;           
   assign axi_master_arid_o[AXI_ID-1:0] = axi_master_arid_int[AXI_ID-1:0];
   assign axi_master_aruser_o           = axi_master_aruser_int;          
   assign axi_master_arready_int        = axi_master_arready_i;  

   assign axi_master_rvalid_int          = axi_master_rvalid_i;         
   assign axi_master_rdata_int           = axi_master_rdata_i;          
   assign axi_master_rresp_int           = axi_master_rresp_i;          
   assign axi_master_ruser_int           = axi_master_ruser_i;          
   assign axi_master_rid_int[AXI_ID-1:0] = axi_master_rid_i[AXI_ID-1:0];
   assign axi_master_rlast_int           = axi_master_rlast_i;          
   assign axi_master_rready_o            = axi_master_rready_int;                


   //  █████╗ ██╗  ██╗██╗         █████╗ ██████╗         ██████╗ ██╗   ██╗███████╗███████╗
   // ██╔══██╗╚██╗██╔╝██║        ██╔══██╗██╔══██╗        ██╔══██╗██║   ██║██╔════╝██╔════╝
   // ███████║ ╚███╔╝ ██║        ███████║██████╔╝        ██████╔╝██║   ██║█████╗  █████╗
   // ██╔══██║ ██╔██╗ ██║        ██╔══██║██╔══██╗        ██╔══██╗██║   ██║██╔══╝  ██╔══╝
   // ██║  ██║██╔╝ ██╗██║███████╗██║  ██║██║  ██║███████╗██████╔╝╚██████╔╝██║     ██║
   // ╚═╝  ╚═╝╚═╝  ╚═╝╚═╝╚══════╝╚═╝  ╚═╝╚═╝  ╚═╝╚══════╝╚═════╝  ╚═════╝ ╚═╝     ╚═╝
   /*axi_ar_buffer
   #(
      .ID_WIDTH     ( AXI_ID      ),
      .ADDR_WIDTH   ( AXI_ADDR    ),
      .USER_WIDTH   ( AXI_USER    ),
      .BUFFER_DEPTH ( 2           )
   )
   i_AXI_AR_BUFFER
   (
      .clk_i           ( clk                                 ),
      .rst_ni          ( rst_n                               ),
      .test_en_i       ( test_en_i                           ),

      .slave_valid_i   ( axi_master_arvalid_int              ),
      .slave_addr_i    ( axi_master_araddr_int               ),
      .slave_prot_i    ( axi_master_arprot_int               ),
      .slave_region_i  ( axi_master_arregion_int             ),
      .slave_len_i     ( axi_master_arlen_int                ),
      .slave_size_i    ( axi_master_arsize_int               ),
      .slave_burst_i   ( axi_master_arburst_int              ),
      .slave_lock_i    ( axi_master_arlock_int               ),
      .slave_cache_i   ( axi_master_arcache_int              ),
      .slave_qos_i     ( axi_master_arqos_int                ),
      .slave_id_i      ( axi_master_arid_int[AXI_ID-1:0]     ),
      .slave_user_i    ( axi_master_aruser_int               ),
      .slave_ready_o   ( axi_master_arready_int              ),

      .master_valid_o  ( axi_master_arvalid_o                ),
      .master_addr_o   ( axi_master_araddr_o                 ),
      .master_prot_o   ( axi_master_arprot_o                 ),
      .master_region_o ( axi_master_arregion_o               ),
      .master_len_o    ( axi_master_arlen_o                  ),
      .master_size_o   ( axi_master_arsize_o                 ),
      .master_burst_o  ( axi_master_arburst_o                ),
      .master_lock_o   ( axi_master_arlock_o                 ),
      .master_cache_o  ( axi_master_arcache_o                ),
      .master_qos_o    ( axi_master_arqos_o                  ),
      .master_id_o     ( axi_master_arid_o[AXI_ID-1:0]       ),
      .master_user_o   ( axi_master_aruser_o                 ),
      .master_ready_i  ( axi_master_arready_i                )
   );

   //  █████╗ ██╗  ██╗██╗        ██████╗         ██████╗ ██╗   ██╗███████╗███████╗
   // ██╔══██╗╚██╗██╔╝██║        ██╔══██╗        ██╔══██╗██║   ██║██╔════╝██╔════╝
   // ███████║ ╚███╔╝ ██║        ██████╔╝        ██████╔╝██║   ██║█████╗  █████╗
   // ██╔══██║ ██╔██╗ ██║        ██╔══██╗        ██╔══██╗██║   ██║██╔══╝  ██╔══╝
   // ██║  ██║██╔╝ ██╗██║███████╗██║  ██║███████╗██████╔╝╚██████╔╝██║     ██║
   // ╚═╝  ╚═╝╚═╝  ╚═╝╚═╝╚══════╝╚═╝  ╚═╝╚══════╝╚═════╝  ╚═════╝ ╚═╝     ╚═╝
   axi_r_buffer
      #(
      .ID_WIDTH       ( AXI_ID                             ),
      .DATA_WIDTH     ( AXI_DATA                           ),
      .USER_WIDTH     ( AXI_USER                           ),
      .BUFFER_DEPTH   ( 2                                  )
   )
   i_AXI_R_BUFFER
   (
      .clk_i          ( clk                                ),
      .rst_ni         ( rst_n                              ),
      .test_en_i      ( test_en_i                          ),

      .slave_valid_i  ( axi_master_rvalid_i                ),
      .slave_data_i   ( axi_master_rdata_i                 ),
      .slave_resp_i   ( axi_master_rresp_i                 ),
      .slave_user_i   ( axi_master_ruser_i                 ),
      .slave_id_i     ( axi_master_rid_i[AXI_ID-1:0]       ),
      .slave_last_i   ( axi_master_rlast_i                 ),
      .slave_ready_o  ( axi_master_rready_o                ),

      .master_valid_o ( axi_master_rvalid_int              ),
      .master_data_o  ( axi_master_rdata_int               ),
      .master_resp_o  ( axi_master_rresp_int               ),
      .master_user_o  ( axi_master_ruser_int               ),
      .master_id_o    ( axi_master_rid_int[AXI_ID-1:0]     ),
      .master_last_o  ( axi_master_rlast_int               ),
      .master_ready_i ( axi_master_rready_int              )
   );*/


   assign axi_master_awid_o     = {AXI_ID{1'b0}};
   assign axi_master_awaddr_o   = {AXI_ADDR{1'b0}};
   assign axi_master_awlen_o    = 8'b0000_0000;
   assign axi_master_awsize_o   = 3'b000;
   assign axi_master_awburst_o  = 2'b00;
   assign axi_master_awlock_o   = 1'b0;
   assign axi_master_awcache_o  = 4'b0000;
   assign axi_master_awprot_o   = 3'b000;
   assign axi_master_awregion_o = 4'b0000;
   assign axi_master_awuser_o   = {AXI_USER{1'b0}};
   assign axi_master_awqos_o    = 4'b0000;
   assign axi_master_awvalid_o  = 1'b0;

   assign axi_master_wdata_o    = {AXI_DATA{1'b0}};
   assign axi_master_wstrb_o    = {AXI_DATA/8{1'b0}};;
   assign axi_master_wlast_o    = 1'b0;
   assign axi_master_wuser_o    =  {AXI_USER{1'b0}};
   assign axi_master_wvalid_o   = 1'b0;

   assign axi_master_bready_o   = 1'b0;
endmodule // top_icache_bank

  

// 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-13 09:36  digital-world  阅读(97)  评论(0编辑  收藏  举报