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