/*************************************************************************************** * Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences * Copyright (c) 2020-2021 Peng Cheng Laboratory * * XiangShan is licensed under Mulan PSL v2. * You can use this software according to the terms and conditions of the Mulan PSL v2. * You may obtain a copy of Mulan PSL v2 at: * http://license.coscl.org.cn/MulanPSL2 * * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * * See the Mulan PSL v2 for more details. ***************************************************************************************/ package xiangshan.cache import org.chipsalliance.cde.config.Parameters import chisel3._ import chisel3.util._ import freechips.rocketchip.tilelink.ClientMetadata import utility.{XSDebug, XSPerfAccumulate, HasPerfEvents} import xiangshan.L1CacheErrorInfo class DcacheStoreRequestIO(implicit p: Parameters) extends DCacheBundle { val cmd = UInt(M_SZ.W) val vaddr = UInt(VAddrBits.W) val instrtype = UInt(sourceTypeWidth.W) } class DCacheStoreIO(implicit p: Parameters) extends DCacheBundle { // Paddr in STA s1, used for hit check val s1_paddr = Output(UInt(PAddrBits.W)) // TLB miss or Exception in STA s1, kill Dcache req val s1_kill = Output(Bool()) // Access Fault or MMIO in STA s2, kill Dcache req val s2_kill = Output(Bool()) // Debug PC val s2_pc = Output(UInt(VAddrBits.W)) val req = DecoupledIO(new DcacheStoreRequestIO) val resp = Flipped(DecoupledIO(new DCacheBundle() { // this store misses (for now, not used) val miss = Bool() // this store needs replay (for now, not used) val replay = Bool() // tag error TODO: add logic val tag_error = Bool() })) } /** Non-Blocking Store Dcache Pipeline * * Associated with STA Pipeline * Issue a store write prefetch to dcache if miss (if EnableStorePrefetchAtIssue) * Issue a prefetch train request to sms if miss (if EnableStorePrefetchSMS) * Recieve prefetch request, Issue a store write prefetch to dcache if miss (if EnableStorePrefetchAtCommit or EnableStorePrefetchSPB) */ class StorePipe(id: Int)(implicit p: Parameters) extends DCacheModule{ val io = IO(new DCacheBundle { // incoming requests val lsu = Flipped(new DCacheStoreIO) // meta and data array read port val meta_read = DecoupledIO(new MetaReadReq) val meta_resp = Input(Vec(nWays, new Meta)) // TODO extra_meta_resp: error; prefetch; access (prefetch hit?) // val extra_meta_resp = Input(Vec(nWays, new DCacheExtraMeta)) val tag_read = DecoupledIO(new TagReadReq) val tag_resp = Input(Vec(nWays, UInt(encTagBits.W))) // send miss request to dcache miss queue val miss_req = DecoupledIO(new MissReq) // update state vec in replacement algo, for now, set this as false val replace_access = ValidIO(new ReplacementAccessBundle) // find the way to be replaced val replace_way = new ReplacementWayReqIO // ecc error val error = Output(ValidIO(new L1CacheErrorInfo)) }) // TODO: error io.error := 0.U.asTypeOf(ValidIO(new L1CacheErrorInfo)) /** S0: * send tag and meta read req */ val s0_valid = io.lsu.req.valid val s0_req = io.lsu.req.bits val s0_fire = io.lsu.req.fire io.meta_read.valid := s0_valid io.meta_read.bits.idx := get_idx(io.lsu.req.bits.vaddr) io.meta_read.bits.way_en := ~0.U(nWays.W) io.tag_read.valid := s0_valid io.tag_read.bits.idx := get_idx(io.lsu.req.bits.vaddr) io.tag_read.bits.way_en := ~0.U(nWays.W) io.lsu.req.ready := io.meta_read.ready && io.tag_read.ready XSPerfAccumulate("s0_valid", io.lsu.req.valid) XSPerfAccumulate("s0_valid_not_ready", io.lsu.req.valid && !io.lsu.req.ready) /** S1: * get tag and meta read resp * judge hit or miss */ def wayMap[T <: Data](f: Int => T) = VecInit((0 until nWays).map(f)) val s1_valid = RegNext(s0_fire) val s1_req = RegEnable(s0_req, s0_fire) val s1_meta_resp = io.meta_resp val s1_tag_resp = io.tag_resp.map(tag => tag(tagBits - 1, 0)) val s1_paddr = io.lsu.s1_paddr /** * get hit meta */ val s1_tag_match = Wire(UInt(nWays.W)) s1_tag_match := wayMap((wayid: Int) => {s1_tag_resp(wayid) === get_tag(s1_paddr) && s1_meta_resp(wayid).coh.isValid()}).asUInt val s1_fake_meta = Wire(new Meta) s1_fake_meta.coh := ClientMetadata.onReset val s1_hit_meta = Mux(s1_tag_match.orR, Mux1H(s1_tag_match, wayMap((wayid: Int) => {s1_meta_resp(wayid)})), s1_fake_meta) val s1_hit_coh = s1_hit_meta.coh val (s1_has_permission, _, s1_new_hit_coh) = s1_hit_coh.onAccess(s1_req.cmd) val s1_hit = s1_has_permission && s1_new_hit_coh === s1_hit_coh && s1_tag_match.orR /** * Don't choose a replace_way anymore */ io.replace_way.set.valid := false.B io.replace_way.set.bits := get_idx(s1_req.vaddr) io.replace_way.dmWay := get_direct_map_way(s1_req.vaddr) val s1_need_replacement = !s1_tag_match.orR /** S2: * miss: send a write hint to Dache * hit : update replace algrithom to make the hited line stay longer */ val s2_valid = RegNext(s1_valid) && RegNext(!io.lsu.s1_kill) val s2_req = RegEnable(s1_req, s1_valid) val s2_hit = RegEnable(s1_hit, s1_valid) val s2_paddr = RegEnable(s1_paddr, s1_valid) val s2_hit_coh = RegEnable(s1_hit_coh, s1_valid) val s2_is_prefetch = RegEnable(s1_req.instrtype === DCACHE_PREFETCH_SOURCE.U, s1_valid) io.lsu.resp.valid := s2_valid io.lsu.resp.bits.miss := !s2_hit io.lsu.resp.bits.replay := false.B // TODO: consider tag error io.lsu.resp.bits.tag_error := false.B /** * send req to Dcache MissQueue */ if(EnableStorePrefetchAtIssue) { // all miss stores, whether prefetched or normal, send requests directly to mshr io.miss_req.valid := s2_valid && !s2_hit }else { // only prefetched miss stores will send requests directly to mshr io.miss_req.valid := s2_valid && !s2_hit && s2_is_prefetch } io.miss_req.bits := DontCare // only send out a prefetch write to Dcache io.miss_req.bits.source := DCACHE_PREFETCH_SOURCE.U io.miss_req.bits.pf_source := L1_HW_PREFETCH_STORE io.miss_req.bits.cmd := MemoryOpConstants.M_PFW io.miss_req.bits.addr := get_block_addr(s2_paddr) io.miss_req.bits.vaddr := s2_req.vaddr io.miss_req.bits.req_coh := s2_hit_coh // TODO: consider tag error io.miss_req.bits.cancel := io.lsu.s2_kill io.miss_req.bits.pc := io.lsu.s2_pc /** * update replacer, for now, disable this */ io.replace_access.valid := false.B io.replace_access.bits := DontCare XSPerfAccumulate("store_fire", s2_valid && !io.lsu.s2_kill) XSPerfAccumulate("sta_hit", s2_valid && s2_hit && !io.lsu.s2_kill) XSPerfAccumulate("sta_miss", s2_valid && !s2_hit && !io.lsu.s2_kill) XSPerfAccumulate("store_miss_prefetch_fire", io.miss_req.fire && !io.miss_req.bits.cancel) XSPerfAccumulate("store_miss_prefetch_not_fire", io.miss_req.valid && !io.miss_req.ready && !io.miss_req.bits.cancel) }