//******************************************************************************** // SPDX-License-Identifier: Apache-2.0 // Copyright 2020 Western Digital Corporation or its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the 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 DATA & TAG MODULE WRAPPER // ///////////////////////////////////////////////////// module el2_ifu_ic_mem import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic clk, // Clock only while core active. Through one clock header. For flops with second clock header built in. Connected to ACTIVE_L2CLK. input logic active_clk, // Clock only while core active. Through two clock headers. For flops without second clock header built in. input logic rst_l, // reset, active low input logic clk_override, // Override non-functional clock gating input logic dec_tlu_core_ecc_disable, // Disable ECC checking input logic [31:1] ic_rw_addr, input logic [pt.ICACHE_NUM_WAYS-1:0] ic_wr_en, // Which way to write input logic ic_rd_en, // Read enable input logic [pt.ICACHE_INDEX_HI:3] ic_debug_addr, // Read/Write addresss to the Icache. input logic ic_debug_rd_en, // Icache debug rd input logic ic_debug_wr_en, // Icache debug wr input logic ic_debug_tag_array, // Debug tag array input logic [pt.ICACHE_NUM_WAYS-1:0] ic_debug_way, // Debug way. Rd or Wr. input logic [63:0] ic_premux_data, // Premux data to be muxed with each way of the Icache. input logic ic_sel_premux_data, // Select the pre_muxed data input logic [pt.ICACHE_BANKS_WAY-1:0][70:0] ic_wr_data, // Data to fill to the Icache. With ECC output logic [63:0] ic_rd_data , // Data read from Icache. 2x64bits + parity bits. F2 stage. With ECC output logic [70:0] ic_debug_rd_data , // Data read from Icache. 2x64bits + parity bits. F2 stage. With ECC output logic [25:0] ictag_debug_rd_data, // Debug icache tag. input logic [70:0] ic_debug_wr_data, // Debug wr cache. output logic [pt.ICACHE_BANKS_WAY-1:0] ic_eccerr, // ecc error per bank output logic [pt.ICACHE_BANKS_WAY-1:0] ic_parerr, // ecc error per bank input logic [pt.ICACHE_NUM_WAYS-1:0] ic_tag_valid, // Valid from the I$ tag valid outside (in flops). input el2_ic_data_ext_in_pkt_t [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0] ic_data_ext_in_pkt, // this is being driven by the top level for soc testing/etc input el2_ic_tag_ext_in_pkt_t [pt.ICACHE_NUM_WAYS-1:0] ic_tag_ext_in_pkt, // this is being driven by the top level for soc testing/etc output logic [pt.ICACHE_NUM_WAYS-1:0] ic_rd_hit, // ic_rd_hit[3:0] output logic ic_tag_perr, // Tag Parity error input logic scan_mode // Flop scan mode control ); EL2_IC_TAG #( .pt(pt) ) ic_tag_inst ( .*, .ic_wr_en (ic_wr_en[pt.ICACHE_NUM_WAYS-1:0]), .ic_debug_addr(ic_debug_addr[pt.ICACHE_INDEX_HI:3]), .ic_rw_addr (ic_rw_addr[31:3]) ); EL2_IC_DATA #( .pt(pt) ) ic_data_inst ( .*, .ic_wr_en (ic_wr_en[pt.ICACHE_NUM_WAYS-1:0]), .ic_debug_addr(ic_debug_addr[pt.ICACHE_INDEX_HI:3]), .ic_rw_addr (ic_rw_addr[31:1]) ); endmodule ///////////////////////////////////////////////// ////// ICACHE DATA MODULE //////////////////// ///////////////////////////////////////////////// module EL2_IC_DATA import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic clk, input logic active_clk, input logic rst_l, input logic clk_override, input logic [ 31:1] ic_rw_addr, input logic [pt.ICACHE_NUM_WAYS-1:0] ic_wr_en, input logic ic_rd_en, // Read enable input logic [pt.ICACHE_BANKS_WAY-1:0][70:0] ic_wr_data, // Data to fill to the Icache. With ECC output logic [63:0] ic_rd_data , // Data read from Icache. 2x64bits + parity bits. F2 stage. With ECC input logic [70:0] ic_debug_wr_data, // Debug wr cache. output logic [70:0] ic_debug_rd_data , // Data read from Icache. 2x64bits + parity bits. F2 stage. With ECC output logic [pt.ICACHE_BANKS_WAY-1:0] ic_parerr, output logic [pt.ICACHE_BANKS_WAY-1:0] ic_eccerr, // ecc error per bank input logic [pt.ICACHE_INDEX_HI:3] ic_debug_addr, // Read/Write addresss to the Icache. input logic ic_debug_rd_en, // Icache debug rd input logic ic_debug_wr_en, // Icache debug wr input logic ic_debug_tag_array, // Debug tag array input logic [pt.ICACHE_NUM_WAYS-1:0] ic_debug_way, // Debug way. Rd or Wr. input logic [63:0] ic_premux_data, // Premux data to be muxed with each way of the Icache. input logic ic_sel_premux_data, // Select the pre_muxed data input logic [pt.ICACHE_NUM_WAYS-1:0] ic_rd_hit, input el2_ic_data_ext_in_pkt_t [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0] ic_data_ext_in_pkt, // this is being driven by the top level for soc testing/etc input logic scan_mode ); logic [pt.ICACHE_TAG_INDEX_LO-1:1] ic_rw_addr_ff; logic [ pt.ICACHE_BANKS_WAY-1:0][ pt.ICACHE_NUM_WAYS-1:0] ic_b_sb_wren; //bank x ways logic [ pt.ICACHE_BANKS_WAY-1:0][ pt.ICACHE_NUM_WAYS-1:0] ic_b_sb_rden; //bank x ways logic [ pt.ICACHE_BANKS_WAY-1:0] ic_b_rden; //bank logic [ pt.ICACHE_BANKS_WAY-1:0] ic_b_rden_ff; //bank logic [ pt.ICACHE_BANKS_WAY-1:0] ic_debug_sel_sb; logic [ pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0][70:0] wb_dout; // ways x bank logic [pt.ICACHE_BANKS_WAY-1:0][70:0] ic_sb_wr_data, ic_bank_wr_data, wb_dout_ecc_bank; logic [pt.ICACHE_NUM_WAYS-1:0][141:0] wb_dout_way_pre; logic [pt.ICACHE_NUM_WAYS-1:0][63:0] wb_dout_way, wb_dout_way_with_premux; logic [141:0] wb_dout_ecc; logic [pt.ICACHE_BANKS_WAY-1:0] bank_check_en; logic [pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_NUM_WAYS-1:0] ic_bank_way_clken; logic [pt.ICACHE_BANKS_WAY-1:0] ic_bank_way_clken_final; logic [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0] ic_bank_way_clken_final_up; logic [pt.ICACHE_NUM_WAYS-1:0] ic_debug_rd_way_en; // debug wr_way logic [pt.ICACHE_NUM_WAYS-1:0] ic_debug_rd_way_en_ff; // debug wr_way logic [pt.ICACHE_NUM_WAYS-1:0] ic_debug_wr_way_en; // debug wr_way logic [pt.ICACHE_INDEX_HI:1] ic_rw_addr_q; logic [pt.ICACHE_BANKS_WAY-1:0] [pt.ICACHE_INDEX_HI : pt.ICACHE_DATA_INDEX_LO] ic_rw_addr_bank_q; logic [pt.ICACHE_TAG_LO-1 : pt.ICACHE_DATA_INDEX_LO] ic_rw_addr_q_inc; logic [pt.ICACHE_NUM_WAYS-1:0] ic_rd_hit_q; logic [pt.ICACHE_BANKS_WAY-1:0] ic_b_sram_en; logic [pt.ICACHE_BANKS_WAY-1:0] ic_b_read_en; logic [pt.ICACHE_BANKS_WAY-1:0] ic_b_write_en; logic [pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_NUM_BYPASS-1:0] [31 : pt.ICACHE_DATA_INDEX_LO] wb_index_hold; logic [pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_NUM_BYPASS-1:0] write_bypass_en; //bank logic [pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_NUM_BYPASS-1:0] write_bypass_en_ff; //bank logic [pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_NUM_BYPASS-1:0] index_valid; //bank logic [pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_NUM_BYPASS-1:0] ic_b_clear_en; logic [pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_NUM_BYPASS-1:0] ic_b_addr_match; logic [pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_NUM_BYPASS-1:0] ic_b_addr_match_index_only; logic [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0] ic_b_sram_en_up; logic [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0] ic_b_read_en_up; logic [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0] ic_b_write_en_up; logic [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_NUM_BYPASS-1:0] [31 : pt.ICACHE_DATA_INDEX_LO] wb_index_hold_up; logic [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_NUM_BYPASS-1:0] write_bypass_en_up; //bank logic [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_NUM_BYPASS-1:0] write_bypass_en_ff_up; //bank logic [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_NUM_BYPASS-1:0] index_valid_up; //bank logic [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_NUM_BYPASS-1:0] ic_b_clear_en_up; logic [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_NUM_BYPASS-1:0] ic_b_addr_match_up; logic [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_NUM_BYPASS-1:0] ic_b_addr_match_index_only_up; logic [pt.ICACHE_BANKS_WAY-1:0][31 : pt.ICACHE_DATA_INDEX_LO] ic_b_rw_addr; logic [pt.ICACHE_BANKS_WAY-1:0][31 : pt.ICACHE_DATA_INDEX_LO] ic_b_rw_addr_index_only; logic [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0] [31 : pt.ICACHE_DATA_INDEX_LO] ic_b_rw_addr_up; logic [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0] [31 : pt.ICACHE_DATA_INDEX_LO] ic_b_rw_addr_index_only_up; logic ic_rd_en_with_debug; logic ic_rw_addr_wrap, ic_cacheline_wrap_ff; logic ic_debug_rd_en_ff; //----------------------------------------------------------- // ----------- Logic section starts here -------------------- //----------------------------------------------------------- assign ic_debug_rd_way_en[pt.ICACHE_NUM_WAYS-1:0] = {pt.ICACHE_NUM_WAYS{ic_debug_rd_en & ~ic_debug_tag_array}} & ic_debug_way[pt.ICACHE_NUM_WAYS-1:0] ; assign ic_debug_wr_way_en[pt.ICACHE_NUM_WAYS-1:0] = {pt.ICACHE_NUM_WAYS{ic_debug_wr_en & ~ic_debug_tag_array}} & ic_debug_way[pt.ICACHE_NUM_WAYS-1:0] ; logic end_of_cache_line; assign end_of_cache_line = (pt.ICACHE_LN_SZ == 7'h40) ? (&ic_rw_addr_q[5:4]) : ic_rw_addr_q[4]; always_comb begin : clkens ic_bank_way_clken = '0; for (int i = 0; i < pt.ICACHE_BANKS_WAY; i++) begin : wr_ens ic_b_sb_wren[i] = ic_wr_en[pt.ICACHE_NUM_WAYS-1:0] | (ic_debug_wr_way_en[pt.ICACHE_NUM_WAYS-1:0] & {pt.ICACHE_NUM_WAYS{ic_debug_addr[pt.ICACHE_BANK_HI : pt.ICACHE_BANK_LO] == i}}) ; ic_debug_sel_sb[i] = (ic_debug_addr[pt.ICACHE_BANK_HI : pt.ICACHE_BANK_LO] == i); ic_sb_wr_data[i] = (ic_debug_sel_sb[i] & ic_debug_wr_en) ? ic_debug_wr_data : ic_bank_wr_data[i] ; ic_b_rden[i] = ic_rd_en_with_debug & ( ( ~ic_rw_addr_q[pt.ICACHE_BANK_HI] & (i==0)) | (( ic_rw_addr_q[pt.ICACHE_BANK_HI] & ic_rw_addr_q[2:1] == 2'b11) & (i==0) & ~end_of_cache_line) | ( ic_rw_addr_q[pt.ICACHE_BANK_HI] & (i==1)) | ((~ic_rw_addr_q[pt.ICACHE_BANK_HI] & ic_rw_addr_q[2:1] == 2'b11) & (i==1)) ) ; ic_b_sb_rden[i] = {pt.ICACHE_NUM_WAYS{ic_b_rden[i]}}; for (int j = 0; j < pt.ICACHE_NUM_WAYS; j++) begin : way_clkens ic_bank_way_clken[i][j] |= ic_b_sb_rden[i][j] | clk_override | ic_b_sb_wren[i][j]; end end // block: wr_ens end // block: clkens // bank read enables assign ic_rd_en_with_debug = (ic_rd_en | ic_debug_rd_en) & ~(|ic_wr_en); assign ic_rw_addr_q[pt.ICACHE_INDEX_HI:1] = (ic_debug_rd_en | ic_debug_wr_en) ? {ic_debug_addr[pt.ICACHE_INDEX_HI:3],2'b0} : ic_rw_addr[pt.ICACHE_INDEX_HI:1] ; assign ic_rw_addr_q_inc[pt.ICACHE_TAG_LO-1:pt.ICACHE_DATA_INDEX_LO] = ic_rw_addr_q[pt.ICACHE_TAG_LO-1 : pt.ICACHE_DATA_INDEX_LO] + 1 ; assign ic_rw_addr_wrap = ic_rw_addr_q[pt.ICACHE_BANK_HI] & (ic_rw_addr_q[2:1] == 2'b11) & ic_rd_en_with_debug & ~(|ic_wr_en[pt.ICACHE_NUM_WAYS-1:0]); assign ic_cacheline_wrap_ff = ic_rw_addr_ff[pt.ICACHE_TAG_INDEX_LO-1:pt.ICACHE_BANK_LO] == {(pt.ICACHE_TAG_INDEX_LO - pt.ICACHE_BANK_LO){1'b1}}; assign ic_rw_addr_bank_q[0] = ~ic_rw_addr_wrap ? ic_rw_addr_q[pt.ICACHE_INDEX_HI:pt.ICACHE_DATA_INDEX_LO] : {ic_rw_addr_q[pt.ICACHE_INDEX_HI: pt.ICACHE_TAG_INDEX_LO] , ic_rw_addr_q_inc[pt.ICACHE_TAG_INDEX_LO-1: pt.ICACHE_DATA_INDEX_LO] } ; assign ic_rw_addr_bank_q[1] = ic_rw_addr_q[pt.ICACHE_INDEX_HI:pt.ICACHE_DATA_INDEX_LO]; rvdffie #( .WIDTH(int'(pt.ICACHE_TAG_INDEX_LO + pt.ICACHE_BANKS_WAY + pt.ICACHE_NUM_WAYS)), .OVERRIDE(1) ) miscff ( .*, .din({ ic_b_rden[pt.ICACHE_BANKS_WAY-1:0], ic_rw_addr_q[pt.ICACHE_TAG_INDEX_LO-1:1], ic_debug_rd_way_en[pt.ICACHE_NUM_WAYS-1:0], ic_debug_rd_en }), .dout({ ic_b_rden_ff[pt.ICACHE_BANKS_WAY-1:0], ic_rw_addr_ff[pt.ICACHE_TAG_INDEX_LO-1:1], ic_debug_rd_way_en_ff[pt.ICACHE_NUM_WAYS-1:0], ic_debug_rd_en_ff }) ); if (pt.ICACHE_WAYPACK == 0) begin : PACKED_0 logic [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_NUM_BYPASS_WIDTH-1:0] wrptr_up; logic [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_NUM_BYPASS_WIDTH-1:0] wrptr_in_up; logic [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_NUM_BYPASS-1:0] sel_bypass_up; logic [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0][pt.ICACHE_NUM_BYPASS-1:0] sel_bypass_ff_up; logic [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0][(71*pt.ICACHE_NUM_WAYS)-1:0] sel_bypass_data_up; logic [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0] any_bypass_up; logic [pt.ICACHE_NUM_WAYS-1:0][pt.ICACHE_BANKS_WAY-1:0] any_addr_match_up; `define EL2_IC_DATA_SRAM(depth, width) \ ram_``depth``x``width ic_bank_sb_way_data ( \ .ME(ic_bank_way_clken_final_up[i][k]), \ .WE (ic_b_sb_wren[k][i]), \ .D (ic_sb_wr_data[k][``width-1:0]), \ .ADR(ic_rw_addr_bank_q[k][pt.ICACHE_INDEX_HI:pt.ICACHE_DATA_INDEX_LO]), \ .Q (wb_dout_pre_up[i][k]), \ .CLK (clk), \ .ROP ( ), \ .TEST1(ic_data_ext_in_pkt[i][k].TEST1), \ .RME(ic_data_ext_in_pkt[i][k].RME), \ .RM(ic_data_ext_in_pkt[i][k].RM), \ \ .LS(ic_data_ext_in_pkt[i][k].LS), \ .DS(ic_data_ext_in_pkt[i][k].DS), \ .SD(ic_data_ext_in_pkt[i][k].SD), \ \ .TEST_RNM(ic_data_ext_in_pkt[i][k].TEST_RNM), \ .BC1(ic_data_ext_in_pkt[i][k].BC1), \ .BC2(ic_data_ext_in_pkt[i][k].BC2) \ ); \ if (pt.ICACHE_BYPASS_ENABLE == 1) begin \ assign wrptr_in_up[i][k] = (wrptr_up[i][k] == (pt.ICACHE_NUM_BYPASS-1)) ? '0 : (wrptr_up[i][k] + 1'd1); \ rvdffs #(pt.ICACHE_NUM_BYPASS_WIDTH) wrptr_ff(.*, .clk(active_clk), .en(|write_bypass_en_up[i][k]), .din (wrptr_in_up[i][k]), .dout(wrptr_up[i][k])) ; \ assign ic_b_sram_en_up[i][k] = ic_bank_way_clken[k][i]; \ assign ic_b_read_en_up[i][k] = ic_b_sram_en_up[i][k] & ic_b_sb_rden[k][i]; \ assign ic_b_write_en_up[i][k] = ic_b_sram_en_up[i][k] & ic_b_sb_wren[k][i]; \ assign ic_bank_way_clken_final_up[i][k] = ic_b_sram_en_up[i][k] & ~(|sel_bypass_up[i][k]); \ assign ic_b_rw_addr_up[i][k] = {ic_rw_addr[31:pt.ICACHE_INDEX_HI+1],ic_rw_addr_bank_q[k]}; \ assign ic_b_rw_addr_index_only_up[i][k] = ic_rw_addr_bank_q[k]; \ always_comb begin \ any_addr_match_up[i][k] = '0; \ for (int l=0; l