// 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. //******************************************************************************** // $Id$ // // // Owner: // Function: Store Buffer // Comments: Dual writes and single drain // // // DC1 -> DC2 -> DC3 -> DC4 (Commit) // // //******************************************************************************** module el2_lsu_stbuf import el2_pkg::*; #( `include "el2_param.vh" ) ( input logic clk, // core clock input logic rst_l, // reset input logic lsu_stbuf_c1_clk, // stbuf clock input logic lsu_free_c2_clk, // free clk // Store Buffer input input logic store_stbuf_reqvld_r, // core instruction goes to stbuf input logic lsu_commit_r, // lsu commits input logic dec_lsu_valid_raw_d, // Speculative decode valid input logic [pt.DCCM_DATA_WIDTH-1:0] store_data_hi_r, // merged data from the dccm for stores. This is used for fwding input logic [pt.DCCM_DATA_WIDTH-1:0] store_data_lo_r, // merged data from the dccm for stores. This is used for fwding input logic [pt.DCCM_DATA_WIDTH-1:0] store_datafn_hi_r, // merged data from the dccm for stores input logic [pt.DCCM_DATA_WIDTH-1:0] store_datafn_lo_r, // merged data from the dccm for stores // Store Buffer output output logic stbuf_reqvld_any, // stbuf is draining output logic stbuf_reqvld_flushed_any, // Top entry is flushed output logic [pt.LSU_SB_BITS-1:0] stbuf_addr_any, // address output logic [pt.DCCM_DATA_WIDTH-1:0] stbuf_data_any, // stbuf data input logic lsu_stbuf_commit_any, // pop the stbuf as it commite output logic lsu_stbuf_full_any, // stbuf is full output logic lsu_stbuf_empty_any, // stbuf is empty output logic ldst_stbuf_reqvld_r, // needed for clocking input logic [pt.LSU_SB_BITS-1:0] lsu_addr_d, // lsu address D-stage input logic [31:0] lsu_addr_m, // lsu address M-stage input logic [31:0] lsu_addr_r, // lsu address R-stage input logic [pt.LSU_SB_BITS-1:0] end_addr_d, // lsu end address D-stage - needed to check unaligned input logic [31:0] end_addr_m, // lsu end address M-stage - needed to check unaligned input logic [31:0] end_addr_r, // lsu end address R-stage - needed to check unaligned input logic ldst_dual_d, ldst_dual_m, ldst_dual_r, input logic addr_in_dccm_m, // address is in dccm input logic addr_in_dccm_r, // address is in dccm // Forwarding signals input logic lsu_cmpen_m, // needed for forwarding stbuf - load input el2_lsu_pkt_t lsu_pkt_m, // LSU packet M-stage input el2_lsu_pkt_t lsu_pkt_r, // LSU packet R-stage output logic [pt.DCCM_DATA_WIDTH-1:0] stbuf_fwddata_hi_m, // stbuf data output logic [pt.DCCM_DATA_WIDTH-1:0] stbuf_fwddata_lo_m, // stbuf data output logic [pt.DCCM_BYTE_WIDTH-1:0] stbuf_fwdbyteen_hi_m, // stbuf data output logic [pt.DCCM_BYTE_WIDTH-1:0] stbuf_fwdbyteen_lo_m, // stbuf data input logic scan_mode // Scan mode ); localparam DEPTH = pt.LSU_STBUF_DEPTH; localparam DATA_WIDTH = pt.DCCM_DATA_WIDTH; localparam BYTE_WIDTH = pt.DCCM_BYTE_WIDTH; localparam DEPTH_LOG2 = $clog2(DEPTH); // These are the fields in the store queue logic [DEPTH-1:0] stbuf_vld; logic [DEPTH-1:0] stbuf_dma_kill; logic [DEPTH-1:0][pt.LSU_SB_BITS-1:0] stbuf_addr; logic [DEPTH-1:0][BYTE_WIDTH-1:0] stbuf_byteen; logic [DEPTH-1:0][DATA_WIDTH-1:0] stbuf_data; logic [DEPTH-1:0] sel_lo; logic [DEPTH-1:0] stbuf_wr_en; logic [DEPTH-1:0] stbuf_dma_kill_en; logic [DEPTH-1:0] stbuf_reset; logic [DEPTH-1:0][pt.LSU_SB_BITS-1:0] stbuf_addrin; logic [DEPTH-1:0][DATA_WIDTH-1:0] stbuf_datain; logic [DEPTH-1:0][BYTE_WIDTH-1:0] stbuf_byteenin; logic [7:0] store_byteen_ext_r; logic [BYTE_WIDTH-1:0] store_byteen_hi_r; logic [BYTE_WIDTH-1:0] store_byteen_lo_r; logic WrPtrEn, RdPtrEn; logic [DEPTH_LOG2-1:0] WrPtr, RdPtr; logic [DEPTH_LOG2-1:0] NxtWrPtr, NxtRdPtr; logic [DEPTH_LOG2-1:0] WrPtrPlus1, WrPtrPlus2, RdPtrPlus1; logic dual_stbuf_write_r; logic isdccmst_m, isdccmst_r; logic [3:0] stbuf_numvld_any, stbuf_specvld_any; logic [1:0] stbuf_specvld_m, stbuf_specvld_r; logic [pt.LSU_SB_BITS-1:$clog2(BYTE_WIDTH)] cmpaddr_hi_m, cmpaddr_lo_m; // variables to detect matching from the store queue logic [DEPTH-1:0] stbuf_match_hi, stbuf_match_lo; logic [DEPTH-1:0][BYTE_WIDTH-1:0] stbuf_fwdbyteenvec_hi, stbuf_fwdbyteenvec_lo; logic [DATA_WIDTH-1:0] stbuf_fwddata_hi_pre_m, stbuf_fwddata_lo_pre_m; logic [BYTE_WIDTH-1:0] stbuf_fwdbyteen_hi_pre_m, stbuf_fwdbyteen_lo_pre_m; // logic to detect matching from the pipe - needed for store - load forwarding logic [BYTE_WIDTH-1:0] ld_byte_rhit_lo_lo, ld_byte_rhit_hi_lo, ld_byte_rhit_lo_hi, ld_byte_rhit_hi_hi; logic ld_addr_rhit_lo_lo, ld_addr_rhit_hi_lo, ld_addr_rhit_lo_hi, ld_addr_rhit_hi_hi; logic [BYTE_WIDTH-1:0] ld_byte_hit_lo, ld_byte_rhit_lo; logic [BYTE_WIDTH-1:0] ld_byte_hit_hi, ld_byte_rhit_hi; logic [BYTE_WIDTH-1:0] ldst_byteen_hi_r; logic [BYTE_WIDTH-1:0] ldst_byteen_lo_r; // byte_en flowing down logic [7:0] ldst_byteen_r; logic [7:0] ldst_byteen_ext_r; // fwd data through the pipe logic [31:0] ld_fwddata_rpipe_lo; logic [31:0] ld_fwddata_rpipe_hi; // coalescing signals logic [DEPTH-1:0] store_matchvec_lo_r, store_matchvec_hi_r; logic store_coalesce_lo_r, store_coalesce_hi_r; //---------------------------------------- // Logic starts here //---------------------------------------- // Create high/low byte enables assign store_byteen_ext_r[7:0] = ldst_byteen_r[7:0] << lsu_addr_r[1:0]; assign store_byteen_hi_r[BYTE_WIDTH-1:0] = store_byteen_ext_r[7:4] & {4{lsu_pkt_r.store}}; assign store_byteen_lo_r[BYTE_WIDTH-1:0] = store_byteen_ext_r[3:0] & {4{lsu_pkt_r.store}}; assign RdPtrPlus1[DEPTH_LOG2-1:0] = RdPtr[DEPTH_LOG2-1:0] + 1'b1; assign WrPtrPlus1[DEPTH_LOG2-1:0] = WrPtr[DEPTH_LOG2-1:0] + 1'b1; assign WrPtrPlus2[DEPTH_LOG2-1:0] = WrPtr[DEPTH_LOG2-1:0] + 2'b10; // ecc error on both hi/lo assign dual_stbuf_write_r = ldst_dual_r & store_stbuf_reqvld_r; assign ldst_stbuf_reqvld_r = ((lsu_commit_r | lsu_pkt_r.dma) & store_stbuf_reqvld_r); // Store Buffer coalescing for (genvar i=0; i= DEPTH) : (stbuf_specvld_any[3:0] >= (DEPTH-1)); assign lsu_stbuf_empty_any = (stbuf_numvld_any[3:0] == 4'b0); // Load forwarding logic from the store queue assign cmpaddr_hi_m[pt.LSU_SB_BITS-1:$clog2(BYTE_WIDTH)] = end_addr_m[pt.LSU_SB_BITS-1:$clog2(BYTE_WIDTH)]; assign cmpaddr_lo_m[pt.LSU_SB_BITS-1:$clog2(BYTE_WIDTH)] = lsu_addr_m[pt.LSU_SB_BITS-1:$clog2(BYTE_WIDTH)]; always_comb begin: GenLdFwd stbuf_fwdbyteen_hi_pre_m[BYTE_WIDTH-1:0] = '0; stbuf_fwdbyteen_lo_pre_m[BYTE_WIDTH-1:0] = '0; for (int i=0; i (lsu_pkt_r.valid & lsu_pkt_r.store & addr_in_dccm_r); endproperty assert_stbuf_wren_store_dccm: assert property (stbuf_wren_store_dccm) else $display("Illegal store buffer write"); `endif endmodule