// SPDX-License-Identifier: Apache-2.0 // Copyright 2019 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 lsu_stbuf import swerv_types::*; ( input logic clk, // core clock input logic rst_l, // reset input logic lsu_freeze_c2_dc2_clk, // freeze clock input logic lsu_freeze_c2_dc3_clk, // freeze clock input logic lsu_freeze_c1_dc2_clk, // freeze clock input logic lsu_freeze_c1_dc3_clk, // freeze clock input logic lsu_freeze_c1_dc3_clken, input logic lsu_c1_dc4_clk, // lsu pipe clock input logic lsu_c1_dc5_clk, // lsu pipe clock input logic lsu_c2_dc4_clk, // lsu pipe clock input logic lsu_c2_dc5_clk, // lsu pipe clock input logic lsu_stbuf_c1_clk, // stbuf clock input logic lsu_free_c2_clk, // free clk // Store Buffer input input logic load_stbuf_reqvld_dc3, // core instruction goes to stbuf input logic store_stbuf_reqvld_dc3, // core instruction goes to stbuf //input logic ldst_stbuf_reqvld_dc3, input logic addr_in_pic_dc2, // address is in pic input logic addr_in_pic_dc3, // address is in pic input logic addr_in_dccm_dc2, // address is in pic input logic addr_in_dccm_dc3, // address is in pic input logic [`RV_DCCM_DATA_WIDTH-1:0] store_ecc_datafn_hi_dc3, // data to write input logic [`RV_DCCM_DATA_WIDTH-1:0] store_ecc_datafn_lo_dc3, // data to write input logic isldst_dc1, // instruction in dc1 is lsu input logic dccm_ldst_dc2, // instruction in dc2 is lsu input logic dccm_ldst_dc3, // instruction in dc3 is lsu input logic single_ecc_error_hi_dc3, // single ecc error in hi bank input logic single_ecc_error_lo_dc3, // single ecc error in lo bank input logic lsu_single_ecc_error_dc5, // single_ecc_error in either bank staged to the dc5 - needed for the load repairs input logic lsu_commit_dc5, // lsu commits input logic lsu_freeze_dc3, // lsu freeze input logic flush_prior_dc5, // Flush is due to i0 and ld/st is in i1 // Store Buffer output output logic stbuf_reqvld_any, // stbuf is draining output logic stbuf_reqvld_flushed_any, // Top entry is flushed output logic stbuf_addr_in_pic_any, // address maps to pic output logic [`RV_DCCM_BYTE_WIDTH-1:0] stbuf_byteen_any, // which bytes are active output logic [`RV_LSU_SB_BITS-1:0] stbuf_addr_any, // address output logic [`RV_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 lsu_stbuf_nodma_empty_any, // stbuf is empty except dma input logic [`RV_LSU_SB_BITS-1:0] lsu_addr_dc1, // lsu address input logic [`RV_LSU_SB_BITS-1:0] lsu_addr_dc2, input logic [`RV_LSU_SB_BITS-1:0] lsu_addr_dc3, input logic [`RV_LSU_SB_BITS-1:0] end_addr_dc1, // lsu end addrress - needed to check unaligned input logic [`RV_LSU_SB_BITS-1:0] end_addr_dc2, input logic [`RV_LSU_SB_BITS-1:0] end_addr_dc3, // Forwarding signals input logic lsu_cmpen_dc2, // needed for forwarding stbuf - load input lsu_pkt_t lsu_pkt_dc2, input lsu_pkt_t lsu_pkt_dc3, input lsu_pkt_t lsu_pkt_dc5, output logic [`RV_DCCM_DATA_WIDTH-1:0] stbuf_fwddata_hi_dc3, // stbuf data output logic [`RV_DCCM_DATA_WIDTH-1:0] stbuf_fwddata_lo_dc3, output logic [`RV_DCCM_BYTE_WIDTH-1:0] stbuf_fwdbyteen_hi_dc3, output logic [`RV_DCCM_BYTE_WIDTH-1:0] stbuf_fwdbyteen_lo_dc3, input logic scan_mode ); `include "global.h" localparam DEPTH = LSU_STBUF_DEPTH; localparam DATA_WIDTH = DCCM_DATA_WIDTH; localparam BYTE_WIDTH = DCCM_BYTE_WIDTH; localparam DEPTH_LOG2 = $clog2(DEPTH); logic [DEPTH-1:0] stbuf_data_vld; logic [DEPTH-1:0] stbuf_drain_vld; logic [DEPTH-1:0] stbuf_flush_vld; logic [DEPTH-1:0] stbuf_addr_in_pic; logic [DEPTH-1:0] stbuf_dma; logic [DEPTH-1:0][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_data_en; logic [DEPTH-1:0] stbuf_drain_or_flush_en; logic [DEPTH-1:0] stbuf_flush_en; logic [DEPTH-1:0] stbuf_drain_en; logic [DEPTH-1:0] stbuf_reset; logic [DEPTH-1:0][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] ldst_byteen_dc3; logic [7:0] store_byteen_ext_dc3; logic [BYTE_WIDTH-1:0] store_byteen_hi_dc3; logic [BYTE_WIDTH-1:0] store_byteen_lo_dc3; logic ldst_stbuf_reqvld_dc3; logic dual_ecc_error_dc3; logic dual_stbuf_write_dc3; logic WrPtrEn, RdPtrEn; logic [DEPTH_LOG2-1:0] WrPtr, RdPtr; logic [DEPTH_LOG2-1:0] NxtWrPtr, NxtRdPtr; logic [DEPTH_LOG2-1:0] WrPtrPlus1, WrPtrPlus1_dc5, WrPtrPlus2, RdPtrPlus1; logic [DEPTH_LOG2-1:0] WrPtr_dc3, WrPtr_dc4, WrPtr_dc5; logic ldst_dual_dc1, ldst_dual_dc2, ldst_dual_dc3, ldst_dual_dc4, ldst_dual_dc5; logic ldst_stbuf_reqvld_dc4, ldst_stbuf_reqvld_dc5; logic dual_stbuf_write_dc4, dual_stbuf_write_dc5; logic [3:0] stbuf_numvld_any, stbuf_specvld_any; logic [1:0] stbuf_specvld_dc1, stbuf_specvld_dc2, stbuf_specvld_dc3; logic stbuf_oneavl_any, stbuf_twoavl_any; logic cmpen_hi_dc2, cmpen_lo_dc2, jit_in_same_region; logic [LSU_SB_BITS-1:$clog2(BYTE_WIDTH)] cmpaddr_hi_dc2, cmpaddr_lo_dc2; logic stbuf_ldmatch_hi_hi, stbuf_ldmatch_hi_lo; logic stbuf_ldmatch_lo_hi, stbuf_ldmatch_lo_lo; logic [BYTE_WIDTH-1:0] stbuf_fwdbyteen_hi_hi, stbuf_fwdbyteen_hi_lo; logic [BYTE_WIDTH-1:0] stbuf_fwdbyteen_lo_hi, stbuf_fwdbyteen_lo_lo; logic [DATA_WIDTH-1:0] stbuf_fwddata_hi_hi, stbuf_fwddata_hi_lo; logic [DATA_WIDTH-1:0] stbuf_fwddata_lo_hi, stbuf_fwddata_lo_lo; logic [DEPTH-1:0] stbuf_ldmatch_hi, stbuf_ldmatch_lo; logic [DEPTH-1:0][BYTE_WIDTH-1:0] stbuf_fwdbyteenvec_hi, stbuf_fwdbyteenvec_lo; logic [DEPTH-1:0][DATA_WIDTH-1:0] stbuf_fwddatavec_hi, stbuf_fwddatavec_lo; logic [DATA_WIDTH-1:0] stbuf_fwddata_hi_dc2, stbuf_fwddata_lo_dc2; logic [DATA_WIDTH-1:0] stbuf_fwddata_hi_fn_dc2, stbuf_fwddata_lo_fn_dc2; logic [BYTE_WIDTH-1:0] stbuf_fwdbyteen_hi_dc2, stbuf_fwdbyteen_lo_dc2; logic [BYTE_WIDTH-1:0] stbuf_fwdbyteen_hi_fn_dc2, stbuf_fwdbyteen_lo_fn_dc2; logic stbuf_load_repair_dc5; //---------------------------------------- // Logic starts here //---------------------------------------- // Create high/low byte enables assign ldst_byteen_dc3[7:0] = ({8{lsu_pkt_dc3.by}} & 8'b0000_0001) | ({8{lsu_pkt_dc3.half}} & 8'b0000_0011) | ({8{lsu_pkt_dc3.word}} & 8'b0000_1111) | ({8{lsu_pkt_dc3.dword}} & 8'b1111_1111); assign store_byteen_ext_dc3[7:0] = ldst_byteen_dc3[7:0] << lsu_addr_dc3[1:0]; assign store_byteen_hi_dc3[BYTE_WIDTH-1:0] = store_byteen_ext_dc3[7:4]; assign store_byteen_lo_dc3[BYTE_WIDTH-1:0] = store_byteen_ext_dc3[3:0]; 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; assign WrPtrPlus1_dc5[DEPTH_LOG2-1:0] = WrPtr_dc5[DEPTH_LOG2-1:0] + 1'b1; // ecc error on both hi/lo assign ldst_dual_dc1 = (lsu_addr_dc1[2] != end_addr_dc1[2]); assign dual_ecc_error_dc3 = (single_ecc_error_hi_dc3 & single_ecc_error_lo_dc3); assign dual_stbuf_write_dc3 = ldst_dual_dc3 & (store_stbuf_reqvld_dc3 | dual_ecc_error_dc3); assign ldst_stbuf_reqvld_dc3 = store_stbuf_reqvld_dc3 | (load_stbuf_reqvld_dc3 & (dual_ecc_error_dc3 ? stbuf_twoavl_any : stbuf_oneavl_any)); // Don't correct ecc if not enough entries. Load will be flushed and come back again assign stbuf_load_repair_dc5 = lsu_single_ecc_error_dc5 & (lsu_pkt_dc5.valid & lsu_pkt_dc5.load & ~flush_prior_dc5); // Store Buffer instantiation for (genvar i=0; i (DEPTH - 2)); assign lsu_stbuf_empty_any = (stbuf_numvld_any[3:0] == 4'b0); assign lsu_stbuf_nodma_empty_any = ~(|(stbuf_data_vld[DEPTH-1:0] & ~stbuf_dma[DEPTH-1:0])); assign stbuf_oneavl_any = (stbuf_numvld_any[3:0] < DEPTH); assign stbuf_twoavl_any = (stbuf_numvld_any[3:0] < (DEPTH - 1)); // Load forwarding logic assign cmpen_hi_dc2 = lsu_cmpen_dc2 & ldst_dual_dc2; assign cmpaddr_hi_dc2[LSU_SB_BITS-1:$clog2(BYTE_WIDTH)] = end_addr_dc2[LSU_SB_BITS-1:$clog2(BYTE_WIDTH)]; assign cmpen_lo_dc2 = lsu_cmpen_dc2; assign cmpaddr_lo_dc2[LSU_SB_BITS-1:$clog2(BYTE_WIDTH)] = lsu_addr_dc2[LSU_SB_BITS-1:$clog2(BYTE_WIDTH)]; assign jit_in_same_region = (addr_in_pic_dc2 & addr_in_pic_dc3) | (addr_in_dccm_dc2 & addr_in_dccm_dc3); // JIT forwarding assign stbuf_ldmatch_hi_hi = (end_addr_dc3[LSU_SB_BITS-1:$clog2(BYTE_WIDTH)] == cmpaddr_hi_dc2[LSU_SB_BITS-1:$clog2(BYTE_WIDTH)]) & ~(cmpen_hi_dc2 & lsu_pkt_dc2.dma & ~lsu_pkt_dc3.dma) & jit_in_same_region; assign stbuf_ldmatch_hi_lo = (lsu_addr_dc3[LSU_SB_BITS-1:$clog2(BYTE_WIDTH)] == cmpaddr_hi_dc2[LSU_SB_BITS-1:$clog2(BYTE_WIDTH)]) & ~(cmpen_hi_dc2 & lsu_pkt_dc2.dma & ~lsu_pkt_dc3.dma) & jit_in_same_region; assign stbuf_ldmatch_lo_hi = (end_addr_dc3[LSU_SB_BITS-1:$clog2(BYTE_WIDTH)] == cmpaddr_lo_dc2[LSU_SB_BITS-1:$clog2(BYTE_WIDTH)]) & ~(cmpen_lo_dc2 & lsu_pkt_dc2.dma & ~lsu_pkt_dc3.dma) & jit_in_same_region; assign stbuf_ldmatch_lo_lo = (lsu_addr_dc3[LSU_SB_BITS-1:$clog2(BYTE_WIDTH)] == cmpaddr_lo_dc2[LSU_SB_BITS-1:$clog2(BYTE_WIDTH)]) & ~(cmpen_lo_dc2 & lsu_pkt_dc2.dma & ~lsu_pkt_dc3.dma) & jit_in_same_region; for (genvar i=0; i