Project Full coverage report
Current view: Cores-VeeR-EL2—Cores-VeeR-EL2—design—ifu—el2_ifu_iccm_mem.sv Coverage Hit Total
Test Date: 21-11-2024 Toggle 97.1% 34 35
Test: all Branch 100.0% 9 9

            Line data    Source code
       1              : //********************************************************************************
       2              : // SPDX-License-Identifier: Apache-2.0
       3              : // Copyright 2020 Western Digital Corporation or its affiliates.
       4              : // Copyright (c) 2023 Antmicro <www.antmicro.com>
       5              : //
       6              : // Licensed under the Apache License, Version 2.0 (the "License");
       7              : // you may not use this file except in compliance with the License.
       8              : // You may obtain a copy of the License at
       9              : //
      10              : // http://www.apache.org/licenses/LICENSE-2.0
      11              : //
      12              : // Unless required by applicable law or agreed to in writing, software
      13              : // distributed under the License is distributed on an "AS IS" BASIS,
      14              : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      15              : // See the License for the specific language governing permissions and
      16              : // limitations under the License.
      17              : //********************************************************************************
      18              : 
      19              : //********************************************************************************
      20              : // Icache closely coupled memory --- ICCM
      21              : //********************************************************************************
      22              : 
      23              : module el2_ifu_iccm_mem
      24              : import el2_pkg::*;
      25              : #(
      26              : `include "el2_param.vh"
      27              :  )(
      28     69844592 :    input logic                                        clk,                                 // Clock only while core active.  Through one clock header.  For flops with    second clock header built in.  Connected to ACTIVE_L2CLK.
      29     69844592 :    input logic                                        active_clk,                          // Clock only while core active.  Through two clock headers. For flops without second clock header built in.
      30          339 :    input logic                                        rst_l,                               // reset, active low
      31            2 :    input logic                                        clk_override,                        // Override non-functional clock gating
      32              : 
      33         1074 :    input logic                                        iccm_wren,                           // ICCM write enable
      34       134206 :    input logic                                        iccm_rden,                           // ICCM read enable
      35       160586 :    input logic [pt.ICCM_BITS-1:1]                     iccm_rw_addr,                        // ICCM read/write address
      36            8 :    input logic                                        iccm_buf_correct_ecc,                // ICCM is doing a single bit error correct cycle
      37            8 :    input logic                                        iccm_correction_state,               // ICCM under a correction - This is needed to guard replacements when hit
      38            1 :    input logic [2:0]                                  iccm_wr_size,                        // ICCM write size
      39          249 :    input logic [77:0]                                 iccm_wr_data,                        // ICCM write data
      40              : 
      41              :    el2_mem_if.veer_iccm                               iccm_mem_export,                     // RAM repositioned in testbench and connected by this interface
      42              : 
      43       136799 :    output logic [63:0]                                iccm_rd_data,                        // ICCM read data
      44       161531 :    output logic [77:0]                                iccm_rd_data_ecc,                    // ICCM read ecc
      45              :    // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core.
      46              :    /*verilator coverage_off*/
      47              :    input  logic                                       scan_mode                            // Scan mode control
      48              :    /*verilator coverage_on*/
      49              : 
      50              : );
      51              : 
      52              : 
      53           16 :    logic [pt.ICCM_NUM_BANKS-1:0]                                                wren_bank;
      54       262048 :    logic [pt.ICCM_NUM_BANKS-1:0]                                                rden_bank;
      55       262066 :    logic [pt.ICCM_NUM_BANKS-1:0]                                                iccm_clken;
      56       160058 :    logic [pt.ICCM_NUM_BANKS-1:0] [pt.ICCM_BITS-1:pt.ICCM_BANK_INDEX_LO] addr_bank;
      57              : 
      58        22051 :    logic [pt.ICCM_NUM_BANKS-1:0] [38:0]  iccm_bank_dout, iccm_bank_dout_fn;
      59          248 :    logic [pt.ICCM_NUM_BANKS-1:0] [38:0]  iccm_bank_wr_data;
      60       159875 :    logic [pt.ICCM_BITS-1:1]              addr_bank_inc;
      61      4257238 :    logic [pt.ICCM_BANK_HI : 2]           iccm_rd_addr_hi_q;
      62       474893 :    logic [pt.ICCM_BANK_HI : 1]           iccm_rd_addr_lo_q;
      63       161531 :    logic             [63:0]              iccm_rd_data_pre;
      64       136799 :    logic             [63:0]              iccm_data;
      65            1 :    logic [1:0]                           addr_incr;
      66          248 :    logic [pt.ICCM_NUM_BANKS-1:0] [38:0]  iccm_bank_wr_data_vec;
      67              : 
      68              :    // logic to handle hard persisten faults
      69            0 :    logic [1:0] [pt.ICCM_BITS-1:2]        redundant_address;
      70            1 :    logic [1:0] [38:0]                    redundant_data;
      71            1 :    logic [1:0]                           redundant_valid;
      72            8 :    logic [pt.ICCM_NUM_BANKS-1:0]         sel_red1, sel_red0, sel_red1_q, sel_red0_q;
      73              : 
      74              : 
      75          246 :    logic [38:0]                          redundant_data0_in, redundant_data1_in;
      76            5 :    logic                                 redundant_lru, redundant_lru_in, redundant_lru_en;
      77            6 :    logic                                 redundant_data0_en;
      78            6 :    logic                                 redundant_data1_en;
      79            4 :    logic                                 r0_addr_en, r1_addr_en;
      80              : 
      81              :    // Testing persistent flip
      82              :    //   logic [3:0]                              not_iccm_bank_dout;
      83              :    //   logic [15:3]                     ecc_insert_flip_in, ecc_insert_flip;
      84              :    //   logic                                 flip_en, flip_match, flip_match_q;
      85              :    //
      86              :    //   assign      flip_in = (iccm_rw_addr[3:2] != 2'b00);    // dont flip when bank0 - this is to make some progress in DMA streaming cases
      87              :    //   assign      flip_en = iccm_rden;
      88              :    //
      89              :    //   rvdffs #(1) flipmatch  (.*,
      90              :    //                   .clk(clk),
      91              :    //                   .din(flip_in),
      92              :    //                   .en(flip_en),
      93              :    //                   .dout(flip_match_q));
      94              :    //
      95              :    // end of testing flip
      96              : 
      97              : 
      98              :    assign addr_incr[1:0]                    = (iccm_wr_size[1:0] == 2'b11) ?  2'b10: 2'b01;
      99              :    assign addr_bank_inc[pt.ICCM_BITS-1 : 1] = iccm_rw_addr[pt.ICCM_BITS-1 : 1] + addr_incr[1:0];
     100              : 
     101              :    for (genvar i=0; i<pt.ICCM_NUM_BANKS/2; i++) begin: mem_bank_data
     102              :       assign iccm_bank_wr_data_vec[(2*i)]   = iccm_wr_data[38:0];
     103              :       assign iccm_bank_wr_data_vec[(2*i)+1] = iccm_wr_data[77:39];
     104              :    end
     105              : 
     106         1360 :    for (genvar i=0; i<pt.ICCM_NUM_BANKS; i++) begin: mem_bank
     107              :       assign wren_bank[i]         = iccm_wren & ((iccm_rw_addr[pt.ICCM_BANK_HI:2] == i) | (addr_bank_inc[pt.ICCM_BANK_HI:2] == i));
     108              :       assign iccm_bank_wr_data[i] = iccm_bank_wr_data_vec[i];
     109              :       assign rden_bank[i]         = iccm_rden & ( (iccm_rw_addr[pt.ICCM_BANK_HI:2] == i) | (addr_bank_inc[pt.ICCM_BANK_HI:2] == i));
     110              :       assign iccm_clken[i]        =  wren_bank[i] | rden_bank[i] | clk_override;
     111              :       assign addr_bank[i][pt.ICCM_BITS-1 : pt.ICCM_BANK_INDEX_LO] = wren_bank[i] ? iccm_rw_addr[pt.ICCM_BITS-1 : pt.ICCM_BANK_INDEX_LO] :
     112              :                                                                                       ((addr_bank_inc[pt.ICCM_BANK_HI:2] == i) ?
     113              :                                                                                                     addr_bank_inc[pt.ICCM_BITS-1 : pt.ICCM_BANK_INDEX_LO] :
     114              :                                                                                                     iccm_rw_addr[pt.ICCM_BITS-1 : pt.ICCM_BANK_INDEX_LO]);
     115              : 
     116         1360 :     always_comb begin
     117         1360 :       iccm_mem_export.iccm_clken[i]        = iccm_clken[i];
     118         1360 :       iccm_mem_export.iccm_wren_bank[i]    = wren_bank[i];
     119         1360 :       iccm_mem_export.iccm_addr_bank[i]    = addr_bank[i];
     120         1360 :       iccm_mem_export.iccm_bank_wr_data[i] = iccm_bank_wr_data[i][31:0];
     121         1360 :       iccm_mem_export.iccm_bank_wr_ecc[i]  = iccm_bank_wr_data[i][32+pt.ICCM_ECC_WIDTH-1:32];
     122         1360 :       iccm_bank_dout[i][31:0]              = iccm_mem_export.iccm_bank_dout[i];
     123         1360 :       iccm_bank_dout[i][32+pt.ICCM_ECC_WIDTH-1:32] = iccm_mem_export.iccm_bank_ecc[i];
     124              :     end
     125              : 
     126              :     // match the redundant rows
     127              :     assign sel_red1[i]  = (redundant_valid[1]  & (((iccm_rw_addr[pt.ICCM_BITS-1:2] == redundant_address[1][pt.ICCM_BITS-1:2]) & (iccm_rw_addr[3:2] == i)) |
     128              :                                                  ((addr_bank_inc[pt.ICCM_BITS-1:2]== redundant_address[1][pt.ICCM_BITS-1:2]) & (addr_bank_inc[3:2] == i))));
     129              : 
     130              :     assign sel_red0[i]  = (redundant_valid[0]  & (((iccm_rw_addr[pt.ICCM_BITS-1:2] == redundant_address[0][pt.ICCM_BITS-1:2]) & (iccm_rw_addr[3:2] == i)) |
     131              :                                                  ((addr_bank_inc[pt.ICCM_BITS-1:2]== redundant_address[0][pt.ICCM_BITS-1:2]) & (addr_bank_inc[3:2] == i))));
     132              : 
     133              :    rvdff #(1) selred0  (.*,
     134              :                    .clk(active_clk),
     135              :                    .din(sel_red0[i]),
     136              :                    .dout(sel_red0_q[i]));
     137              : 
     138              :    rvdff #(1) selred1  (.*,
     139              :                    .clk(active_clk),
     140              :                    .din(sel_red1[i]),
     141              :                    .dout(sel_red1_q[i]));
     142              : 
     143              : 
     144              :   // muxing out the memory data with the redundant data if the address matches
     145              :    assign iccm_bank_dout_fn[i][38:0] = ({39{sel_red1_q[i]}}                         & redundant_data[1][38:0]) |
     146              :                                        ({39{sel_red0_q[i]}}                         & redundant_data[0][38:0]) |
     147              :                                        ({39{~sel_red0_q[i] & ~sel_red1_q[i]}}       & iccm_bank_dout[i][38:0]);
     148              : 
     149              :   end : mem_bank
     150              : // This section does the redundancy for tolerating single bit errors
     151              : // 2x 39 bit data values with address[hi:2] and a valid bit is needed to CAM and sub out the reads/writes to the particular locations
     152              : // Also a LRU flop is kept to decide which of the redundant element to replace.
     153              :    assign r0_addr_en              = ~redundant_lru & iccm_buf_correct_ecc;
     154              :    assign r1_addr_en              = redundant_lru  & iccm_buf_correct_ecc;
     155              :    assign redundant_lru_en         = iccm_buf_correct_ecc | (((|sel_red0[pt.ICCM_NUM_BANKS-1:0]) | (|sel_red1[pt.ICCM_NUM_BANKS-1:0])) & iccm_rden & iccm_correction_state);
     156              :    assign redundant_lru_in        = iccm_buf_correct_ecc ? ~redundant_lru : (|sel_red0[pt.ICCM_NUM_BANKS-1:0]) ? 1'b1 : 1'b0;
     157              : 
     158              :    rvdffs #() red_lru  (.*,                               // LRU flop for the redundant replacements
     159              :                    .clk(active_clk),
     160              :                    .en(redundant_lru_en),
     161              :                    .din(redundant_lru_in),
     162              :                    .dout(redundant_lru));
     163              : 
     164              :     rvdffs #(pt.ICCM_BITS-2) r0_address  (.*,                 // Redundant Row 0 address
     165              :                    .clk(active_clk),
     166              :                    .en(r0_addr_en),
     167              :                    .din(iccm_rw_addr[pt.ICCM_BITS-1:2]),
     168              :                    .dout(redundant_address[0][pt.ICCM_BITS-1:2]));
     169              : 
     170              :    rvdffs #(pt.ICCM_BITS-2) r1_address  (.*,                   // Redundant Row 0 address
     171              :                    .clk(active_clk),
     172              :                    .en(r1_addr_en),
     173              :                    .din(iccm_rw_addr[pt.ICCM_BITS-1:2]),
     174              :                    .dout(redundant_address[1][pt.ICCM_BITS-1:2]));
     175              : 
     176              :     rvdffs #(1) r0_valid  (.*,
     177              :                    .clk(active_clk),                                  // Redundant Row 0 Valid
     178              :                    .en(r0_addr_en),
     179              :                    .din(1'b1),
     180              :                    .dout(redundant_valid[0]));
     181              : 
     182              :    rvdffs #(1) r1_valid  (.*,                                   // Redundant Row 1 Valid
     183              :                    .clk(active_clk),
     184              :                    .en(r1_addr_en),
     185              :                    .din(1'b1),
     186              :                    .dout(redundant_valid[1]));
     187              : 
     188              : 
     189              : 
     190              :    // We will have to update the Redundant copies in addition to the memory on subsequent writes to this memory location.
     191              :    // The data gets updated on : 1) correction cycle, 2) Future writes - this could be W writes from DMA ( match up till addr[2]) or DW writes ( match till address[3])
     192              :    // The data to pick also depends on the current address[2], size and the addr[2] stored in the address field of the redundant flop. Correction cycle is always W write and the data is splat on both legs, so choosing lower Word
     193              : 
     194              :     assign redundant_data0_en      = ((iccm_rw_addr[pt.ICCM_BITS-1:3] == redundant_address[0][pt.ICCM_BITS-1:3]) & ((iccm_rw_addr[2] == redundant_address[0][2]) | (iccm_wr_size[1:0] == 2'b11)) & redundant_valid[0] & iccm_wren) |
     195              :                                       (~redundant_lru & iccm_buf_correct_ecc);
     196              : 
     197              :     assign redundant_data0_in[38:0] = (((iccm_rw_addr[2] == redundant_address[0][2]) & iccm_rw_addr[2]) | (redundant_address[0][2] & (iccm_wr_size[1:0] == 2'b11))) ? iccm_wr_data[77:39]  : iccm_wr_data[38:0];
     198              : 
     199              :     rvdffs #(39) r0_data  (.*,                                 // Redundant Row 1 data
     200              :                    .clk(active_clk),
     201              :                    .en(redundant_data0_en),
     202              :                    .din(redundant_data0_in[38:0]),
     203              :                    .dout(redundant_data[0][38:0]));
     204              : 
     205              :    assign redundant_data1_en      =  ((iccm_rw_addr[pt.ICCM_BITS-1:3] == redundant_address[1][pt.ICCM_BITS-1:3]) & ((iccm_rw_addr[2] == redundant_address[1][2]) | (iccm_wr_size[1:0] == 2'b11)) & redundant_valid[1] & iccm_wren) |
     206              :                                      (redundant_lru & iccm_buf_correct_ecc);
     207              : 
     208              :    assign redundant_data1_in[38:0] = (((iccm_rw_addr[2] == redundant_address[1][2]) & iccm_rw_addr[2]) | (redundant_address[1][2] & (iccm_wr_size[1:0] == 2'b11))) ? iccm_wr_data[77:39]  : iccm_wr_data[38:0];
     209              : 
     210              :     rvdffs #(39) r1_data  (.*,                                  // Redundant Row 1 data
     211              :                    .clk(active_clk),
     212              :                    .en(redundant_data1_en),
     213              :                    .din(redundant_data1_in[38:0]),
     214              :                    .dout(redundant_data[1][38:0]));
     215              : 
     216              : 
     217              :    rvdffs  #(pt.ICCM_BANK_HI)   rd_addr_lo_ff (.*, .clk(active_clk), .din(iccm_rw_addr [pt.ICCM_BANK_HI:1]), .dout(iccm_rd_addr_lo_q[pt.ICCM_BANK_HI:1]), .en(1'b1));   // bit 0 of address is always 0
     218              :    rvdffs  #(pt.ICCM_BANK_BITS) rd_addr_hi_ff (.*, .clk(active_clk), .din(addr_bank_inc[pt.ICCM_BANK_HI:2]), .dout(iccm_rd_addr_hi_q[pt.ICCM_BANK_HI:2]), .en(1'b1));
     219              : 
     220              :    assign iccm_rd_data_pre[63:0] = {iccm_bank_dout_fn[iccm_rd_addr_hi_q][31:0], iccm_bank_dout_fn[iccm_rd_addr_lo_q[pt.ICCM_BANK_HI:2]][31:0]};
     221              :    assign iccm_data[63:0]        = 64'({16'b0, (iccm_rd_data_pre[63:0] >> (16*iccm_rd_addr_lo_q[1]))});
     222              :    assign iccm_rd_data[63:0]     = {iccm_data[63:0]};
     223              :    assign iccm_rd_data_ecc[77:0] = {iccm_bank_dout_fn[iccm_rd_addr_hi_q][38:0], iccm_bank_dout_fn[iccm_rd_addr_lo_q[pt.ICCM_BANK_HI:2]][38:0]};
     224              : 
     225              : endmodule // el2_ifu_iccm_mem