1c6d43980SLemover/*************************************************************************************** 2c6d43980SLemover* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences 3f320e0f0SYinan Xu* Copyright (c) 2020-2021 Peng Cheng Laboratory 4c6d43980SLemover* 5c6d43980SLemover* XiangShan is licensed under Mulan PSL v2. 6c6d43980SLemover* You can use this software according to the terms and conditions of the Mulan PSL v2. 7c6d43980SLemover* You may obtain a copy of Mulan PSL v2 at: 8c6d43980SLemover* http://license.coscl.org.cn/MulanPSL2 9c6d43980SLemover* 10c6d43980SLemover* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 11c6d43980SLemover* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 12c6d43980SLemover* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 13c6d43980SLemover* 14c6d43980SLemover* See the Mulan PSL v2 for more details. 15c6d43980SLemover***************************************************************************************/ 16c6d43980SLemover 17024ee227SWilliam Wangpackage xiangshan.mem 18024ee227SWilliam Wang 198891a219SYinan Xuimport org.chipsalliance.cde.config.Parameters 20024ee227SWilliam Wangimport chisel3._ 21024ee227SWilliam Wangimport chisel3.util._ 22024ee227SWilliam Wangimport utils._ 233c02ee8fSwakafaimport utility._ 24024ee227SWilliam Wangimport xiangshan._ 256ab6918fSYinan Xuimport xiangshan.ExceptionNO._ 26ca2f90a6SLemoverimport xiangshan.backend.fu.PMPRespBundle 27e7ab4635SHuijin Liimport xiangshan.backend.fu.FuType 28730cfbc0SXuan Huimport xiangshan.backend.Bundles.{MemExuInput, MemExuOutput} 297e0f64b0SGuanghui Chengimport xiangshan.backend.fu.NewCSR.TriggerUtil 30f7af4c74Schengguanghuiimport xiangshan.backend.fu.util.SdtrigExt 31*9e12e8edScz4eimport xiangshan.mem.Bundles._ 32bb76fc1bSYanqin Liimport xiangshan.cache.mmu.Pbmt 33*9e12e8edScz4eimport xiangshan.cache.{AtomicWordIO, HasDCacheParameters, MemoryOpConstants} 34*9e12e8edScz4eimport xiangshan.cache.mmu.{TlbCmd, TlbRequestIO} 35*9e12e8edScz4eimport difftest._ 36024ee227SWilliam Wang 37f7af4c74Schengguanghuiclass AtomicsUnit(implicit p: Parameters) extends XSModule 38f7af4c74Schengguanghui with MemoryOpConstants 39f7af4c74Schengguanghui with HasDCacheParameters 40f7af4c74Schengguanghui with SdtrigExt{ 4138c29594Szhanglinjuan 4238c29594Szhanglinjuan val StdCnt = backendParams.StdCnt 4338c29594Szhanglinjuan 44024ee227SWilliam Wang val io = IO(new Bundle() { 45f57f7f2aSYangyu Chen val hartId = Input(UInt(hartIdLen.W)) 463b739f49SXuan Hu val in = Flipped(Decoupled(new MemExuInput)) 4738c29594Szhanglinjuan val storeDataIn = Flipped(Vec(StdCnt, Valid(new MemExuOutput))) 483b739f49SXuan Hu val out = Decoupled(new MemExuOutput) 496786cfb7SWilliam Wang val dcache = new AtomicWordIO 5003efd994Shappy-lx val dtlb = new TlbRequestIO(2) 51ca2f90a6SLemover val pmpResp = Flipped(new PMPRespBundle()) 52024ee227SWilliam Wang val flush_sbuffer = new SbufferFlushBundle 53d87b76aaSWilliam Wang val feedbackSlow = ValidIO(new RSFeedback) 54024ee227SWilliam Wang val redirect = Flipped(ValidIO(new Redirect)) 55ad415ae0SXiaokun-Pei val exceptionInfo = ValidIO(new Bundle { 56db6cfb5aSHaoyuan Feng val vaddr = UInt(XLEN.W) 57db6cfb5aSHaoyuan Feng val gpaddr = UInt(XLEN.W) 58ad415ae0SXiaokun-Pei val isForVSnonLeafPTE = Bool() 59d0de7e4aSpeixiaokun }) 60026615fcSWilliam Wang val csrCtrl = Flipped(new CustomCSRCtrlIO) 61024ee227SWilliam Wang }) 62024ee227SWilliam Wang 63024ee227SWilliam Wang //------------------------------------------------------- 64024ee227SWilliam Wang // Atomics Memory Accsess FSM 65024ee227SWilliam Wang //------------------------------------------------------- 6638c29594Szhanglinjuan val s_invalid :: s_tlb_and_flush_sbuffer_req :: s_pm :: s_wait_flush_sbuffer_resp :: s_cache_req :: s_cache_resp :: s_cache_resp_latch :: s_finish :: s_finish2 :: Nil = Enum(9) 67024ee227SWilliam Wang val state = RegInit(s_invalid) 684f39c746SYinan Xu val out_valid = RegInit(false.B) 691b7adedcSWilliam Wang val data_valid = RegInit(false.B) 7038c29594Szhanglinjuan 7138c29594Szhanglinjuan val uop = Reg(io.in.bits.uop.cloneType) 7238c29594Szhanglinjuan val isLr = LSUOpType.isLr(uop.fuOpType) 7338c29594Szhanglinjuan val isSc = LSUOpType.isSc(uop.fuOpType) 7438c29594Szhanglinjuan val isAMOCAS = LSUOpType.isAMOCAS(uop.fuOpType) 7538c29594Szhanglinjuan val isNotLr = !isLr 7638c29594Szhanglinjuan val isNotSc = !isSc 7738c29594Szhanglinjuan // AMOCAS.Q needs to write two int registers, therefore backend issues two sta uops for AMOCAS.Q. 7838c29594Szhanglinjuan // `pdest2` is used to record the pdest of the second uop 7938c29594Szhanglinjuan val pdest1, pdest2 = Reg(UInt(PhyRegIdxWidth.W)) 8038c29594Szhanglinjuan val pdest1Valid, pdest2Valid = RegInit(false.B) 8138c29594Szhanglinjuan /** 8238c29594Szhanglinjuan * The # of std uops that an atomic instruction require: 8338c29594Szhanglinjuan * (1) For AMOs (except AMOCAS) and LR/SC, 1 std uop is wanted: X(rs2) with uopIdx = 0 8438c29594Szhanglinjuan * (2) For AMOCAS.W/D, 2 std uops are wanted: X(rd), X(rs2) with uopIdx = 0, 1 8538c29594Szhanglinjuan * (3) For AMOCAS.Q, 4 std uops are wanted: X(rd), X(rs2), X(rd+1), X(rs2+1) with uopIdx = 0, 1, 2, 3 8638c29594Szhanglinjuan * stds are not needed for write-back. 8738c29594Szhanglinjuan * 8838c29594Szhanglinjuan * The # of sta uops that an atomic instruction require, also the # of write-back: 8938c29594Szhanglinjuan * (1) For AMOs(except AMOCAS.Q) and LR/SC, 1 sta uop is wanted: X(rs1) with uopIdx = 0 9038c29594Szhanglinjuan * (2) For AMOCAS.Q, 2 sta uop is wanted: X(rs1)*2 with uopIdx = 0, 2 9138c29594Szhanglinjuan */ 9238c29594Szhanglinjuan val rs1, rs2_l, rs2_h, rd_l, rd_h = Reg(UInt(XLEN.W)) 9338c29594Szhanglinjuan val stds = Seq(rd_l, rs2_l, rd_h, rs2_h) 9438c29594Szhanglinjuan val rs2 = Cat(rs2_h, Mux(isAMOCAS, rs2_l, stds.head)) 9538c29594Szhanglinjuan val rd = Cat(rd_h, rd_l) 9638c29594Szhanglinjuan val stdCnt = RegInit(0.U(log2Ceil(stds.length + 1).W)) 9738c29594Szhanglinjuan 980d045bd0SYinan Xu val exceptionVec = RegInit(0.U.asTypeOf(ExceptionVec())) 99204141efSGuanghui Cheng val trigger = RegInit(TriggerAction.None) 100024ee227SWilliam Wang val atom_override_xtval = RegInit(false.B) 1016fce12d9SWilliam Wang val have_sent_first_tlb_req = RegInit(false.B) 102024ee227SWilliam Wang // paddr after translation 103024ee227SWilliam Wang val paddr = Reg(UInt()) 104d0de7e4aSpeixiaokun val gpaddr = Reg(UInt()) 10538c29594Szhanglinjuan val vaddr = rs1 10638c29594Szhanglinjuan 107cff68e26SWilliam Wang val is_mmio = Reg(Bool()) 108ad415ae0SXiaokun-Pei val isForVSnonLeafPTE = Reg(Bool()) 109f9ac118cSHaoyuan Feng 110024ee227SWilliam Wang // dcache response data 111024ee227SWilliam Wang val resp_data = Reg(UInt()) 112f97664b3Swangkaifan val resp_data_wire = WireInit(0.U) 11338c29594Szhanglinjuan val success = Reg(Bool()) 11452180d7eShappy-lx // sbuffer is empty or not 11552180d7eShappy-lx val sbuffer_empty = io.flush_sbuffer.empty 116024ee227SWilliam Wang 11738c29594Szhanglinjuan // Only the least significant AMOFuOpWidth = 6 bits of fuOpType are used, 11838c29594Szhanglinjuan // therefore the MSBs are reused to identify uopIdx 11938c29594Szhanglinjuan val stdUopIdxs = io.storeDataIn.map(_.bits.uop.fuOpType >> LSUOpType.AMOFuOpWidth) 12038c29594Szhanglinjuan val staUopIdx = io.in.bits.uop.fuOpType >> LSUOpType.AMOFuOpWidth 121024ee227SWilliam Wang 122024ee227SWilliam Wang // assign default value to output signals 123024ee227SWilliam Wang io.in.ready := false.B 124024ee227SWilliam Wang 125024ee227SWilliam Wang io.dcache.req.valid := false.B 126024ee227SWilliam Wang io.dcache.req.bits := DontCare 127024ee227SWilliam Wang 128024ee227SWilliam Wang io.dtlb.req.valid := false.B 129024ee227SWilliam Wang io.dtlb.req.bits := DontCare 130c3b763d0SYinan Xu io.dtlb.req_kill := false.B 1319930e66fSLemover io.dtlb.resp.ready := true.B 132024ee227SWilliam Wang 133024ee227SWilliam Wang io.flush_sbuffer.valid := false.B 134024ee227SWilliam Wang 135024ee227SWilliam Wang when (state === s_invalid) { 1364f39c746SYinan Xu when (io.in.fire) { 13738c29594Szhanglinjuan uop := io.in.bits.uop 13838c29594Szhanglinjuan rs1 := io.in.bits.src_rs1 13952180d7eShappy-lx state := s_tlb_and_flush_sbuffer_req 1406fce12d9SWilliam Wang have_sent_first_tlb_req := false.B 1411b7adedcSWilliam Wang } 14282d348fbSLemover } 14382d348fbSLemover 14438c29594Szhanglinjuan when (io.in.fire) { 14538c29594Szhanglinjuan val pdest = io.in.bits.uop.pdest 14638c29594Szhanglinjuan when (staUopIdx === 0.U) { 14738c29594Szhanglinjuan pdest1Valid := true.B 14838c29594Szhanglinjuan pdest1 := pdest 14938c29594Szhanglinjuan }.elsewhen (staUopIdx === 2.U) { 15038c29594Szhanglinjuan pdest2Valid := true.B 15138c29594Szhanglinjuan pdest2 := pdest 15238c29594Szhanglinjuan }.otherwise { 15338c29594Szhanglinjuan assert(false.B, "unrecognized sta uopIdx") 15438c29594Szhanglinjuan } 1551b7adedcSWilliam Wang } 156024ee227SWilliam Wang 15738c29594Szhanglinjuan stds.zipWithIndex.foreach { case (data, i) => 15838c29594Szhanglinjuan val sels = io.storeDataIn.zip(stdUopIdxs).map { case (in, uopIdx) => 15938c29594Szhanglinjuan val sel = in.fire && uopIdx === i.U 16038c29594Szhanglinjuan when (sel) { data := in.bits.data } 16138c29594Szhanglinjuan sel 16238c29594Szhanglinjuan } 16338c29594Szhanglinjuan OneHot.checkOneHot(sels) 16438c29594Szhanglinjuan } 16538c29594Szhanglinjuan stdCnt := stdCnt + PopCount(io.storeDataIn.map(_.fire)) 16638c29594Szhanglinjuan 16738c29594Szhanglinjuan val StdCntNCAS = 1 // LR/SC and AMO need only 1 src besides rs1 16838c29594Szhanglinjuan val StdCntCASWD = 2 // AMOCAS.W/D needs 2 src regs (rs2 and rd) besides rs1 16938c29594Szhanglinjuan val StdCntCASQ = 4 // AMOCAS.Q needs 4 src regs (rs2, rs2+1, rd, rd+1) besides rs1 17038c29594Szhanglinjuan when (!data_valid) { 17138c29594Szhanglinjuan data_valid := state =/= s_invalid && ( 17238c29594Szhanglinjuan LSUOpType.isAMOCASQ(uop.fuOpType) && stdCnt === StdCntCASQ.U || 17338c29594Szhanglinjuan LSUOpType.isAMOCASWD(uop.fuOpType) && stdCnt === StdCntCASWD.U || 17438c29594Szhanglinjuan !isAMOCAS && stdCnt === StdCntNCAS.U 17538c29594Szhanglinjuan ) 17638c29594Szhanglinjuan } 17738c29594Szhanglinjuan assert(stdCnt <= stds.length.U, "unexpected std") 17838c29594Szhanglinjuan assert(!(Cat(io.storeDataIn.map(_.fire)).orR && data_valid), "atomic unit re-receive data") 179024ee227SWilliam Wang 180204141efSGuanghui Cheng // atomic trigger 181204141efSGuanghui Cheng val csrCtrl = io.csrCtrl 182204141efSGuanghui Cheng val tdata = Reg(Vec(TriggerNum, new MatchTriggerIO)) 183204141efSGuanghui Cheng val tEnableVec = RegInit(VecInit(Seq.fill(TriggerNum)(false.B))) 184204141efSGuanghui Cheng tEnableVec := csrCtrl.mem_trigger.tEnableVec 185204141efSGuanghui Cheng when (csrCtrl.mem_trigger.tUpdate.valid) { 186204141efSGuanghui Cheng tdata(csrCtrl.mem_trigger.tUpdate.bits.addr) := csrCtrl.mem_trigger.tUpdate.bits.tdata 187204141efSGuanghui Cheng } 188204141efSGuanghui Cheng 189204141efSGuanghui Cheng val debugMode = csrCtrl.mem_trigger.debugMode 190204141efSGuanghui Cheng val triggerCanRaiseBpExp = csrCtrl.mem_trigger.triggerCanRaiseBpExp 191204141efSGuanghui Cheng val backendTriggerTimingVec = VecInit(tdata.map(_.timing)) 192204141efSGuanghui Cheng val backendTriggerChainVec = VecInit(tdata.map(_.chain)) 193204141efSGuanghui Cheng val backendTriggerHitVec = WireInit(VecInit(Seq.fill(TriggerNum)(false.B))) 194204141efSGuanghui Cheng val backendTriggerCanFireVec = RegInit(VecInit(Seq.fill(TriggerNum)(false.B))) 195204141efSGuanghui Cheng 19638c29594Szhanglinjuan assert(state === s_invalid || 19738c29594Szhanglinjuan uop.fuOpType(1,0) === "b10".U || 19838c29594Szhanglinjuan uop.fuOpType(1,0) === "b11".U || 19938c29594Szhanglinjuan LSUOpType.isAMOCASQ(uop.fuOpType), 20038c29594Szhanglinjuan "Only word or doubleword or quadword is supported" 20138c29594Szhanglinjuan ) 202204141efSGuanghui Cheng 203204141efSGuanghui Cheng // store trigger 204204141efSGuanghui Cheng val store_hit = Wire(Vec(TriggerNum, Bool())) 205204141efSGuanghui Cheng for (j <- 0 until TriggerNum) { 206204141efSGuanghui Cheng store_hit(j) := !tdata(j).select && !debugMode && isNotLr && TriggerCmp( 207204141efSGuanghui Cheng vaddr, 208204141efSGuanghui Cheng tdata(j).tdata2, 209204141efSGuanghui Cheng tdata(j).matchType, 210204141efSGuanghui Cheng tEnableVec(j) && tdata(j).store 211204141efSGuanghui Cheng ) 212204141efSGuanghui Cheng } 213204141efSGuanghui Cheng // load trigger 214204141efSGuanghui Cheng val load_hit = Wire(Vec(TriggerNum, Bool())) 215204141efSGuanghui Cheng for (j <- 0 until TriggerNum) { 216204141efSGuanghui Cheng load_hit(j) := !tdata(j).select && !debugMode && isNotSc && TriggerCmp( 217204141efSGuanghui Cheng vaddr, 218204141efSGuanghui Cheng tdata(j).tdata2, 219204141efSGuanghui Cheng tdata(j).matchType, 220204141efSGuanghui Cheng tEnableVec(j) && tdata(j).load 221204141efSGuanghui Cheng ) 222204141efSGuanghui Cheng } 223204141efSGuanghui Cheng backendTriggerHitVec := store_hit.zip(load_hit).map { case (sh, lh) => sh || lh } 224204141efSGuanghui Cheng // triggerCanFireVec will update at T+1 22538c29594Szhanglinjuan TriggerCheckCanFire(TriggerNum, backendTriggerCanFireVec, backendTriggerHitVec, 22638c29594Szhanglinjuan backendTriggerTimingVec, backendTriggerChainVec) 227204141efSGuanghui Cheng 228204141efSGuanghui Cheng val actionVec = VecInit(tdata.map(_.action)) 229204141efSGuanghui Cheng val triggerAction = Wire(TriggerAction()) 230204141efSGuanghui Cheng TriggerUtil.triggerActionGen(triggerAction, backendTriggerCanFireVec, actionVec, triggerCanRaiseBpExp) 231b0a60050SGuanghui Cheng val triggerDebugMode = TriggerAction.isDmode(triggerAction) 232b0a60050SGuanghui Cheng val triggerBreakpoint = TriggerAction.isExp(triggerAction) 233204141efSGuanghui Cheng 234024ee227SWilliam Wang // tlb translation, manipulating signals && deal with exception 23552180d7eShappy-lx // at the same time, flush sbuffer 23652180d7eShappy-lx when (state === s_tlb_and_flush_sbuffer_req) { 2376fce12d9SWilliam Wang // do not accept tlb resp in the first cycle 2386fce12d9SWilliam Wang // this limition is for hw prefetcher 2396fce12d9SWilliam Wang // when !have_sent_first_tlb_req, tlb resp may come from hw prefetch 2406fce12d9SWilliam Wang have_sent_first_tlb_req := true.B 2416fce12d9SWilliam Wang 2426fce12d9SWilliam Wang when (io.dtlb.resp.fire && have_sent_first_tlb_req) { 24303efd994Shappy-lx paddr := io.dtlb.resp.bits.paddr(0) 244d0de7e4aSpeixiaokun gpaddr := io.dtlb.resp.bits.gpaddr(0) 245189833a1SHaoyuan Feng vaddr := io.dtlb.resp.bits.fullva 246ad415ae0SXiaokun-Pei isForVSnonLeafPTE := io.dtlb.resp.bits.isForVSnonLeafPTE 247024ee227SWilliam Wang // exception handling 24838c29594Szhanglinjuan val addrAligned = LookupTree(uop.fuOpType(1,0), List( 24938c29594Szhanglinjuan "b10".U -> (vaddr(1,0) === 0.U), // W 25038c29594Szhanglinjuan "b11".U -> (vaddr(2,0) === 0.U), // D 25138c29594Szhanglinjuan "b00".U -> (vaddr(3,0) === 0.U) // Q 252024ee227SWilliam Wang )) 2538c343485SWilliam Wang exceptionVec(loadAddrMisaligned) := !addrAligned && isLr 2548c343485SWilliam Wang exceptionVec(storeAddrMisaligned) := !addrAligned && !isLr 25503efd994Shappy-lx exceptionVec(storePageFault) := io.dtlb.resp.bits.excp(0).pf.st 25603efd994Shappy-lx exceptionVec(loadPageFault) := io.dtlb.resp.bits.excp(0).pf.ld 25703efd994Shappy-lx exceptionVec(storeAccessFault) := io.dtlb.resp.bits.excp(0).af.st 25803efd994Shappy-lx exceptionVec(loadAccessFault) := io.dtlb.resp.bits.excp(0).af.ld 259d0de7e4aSpeixiaokun exceptionVec(storeGuestPageFault) := io.dtlb.resp.bits.excp(0).gpf.st 260d0de7e4aSpeixiaokun exceptionVec(loadGuestPageFault) := io.dtlb.resp.bits.excp(0).gpf.ld 261e9092fe2SLemover 262b0a60050SGuanghui Cheng exceptionVec(breakPoint) := triggerBreakpoint 263204141efSGuanghui Cheng trigger := triggerAction 264204141efSGuanghui Cheng 265e9092fe2SLemover when (!io.dtlb.resp.bits.miss) { 2668744445eSMaxpicca-Li io.out.bits.uop.debugInfo.tlbRespTime := GTimer() 267b0a60050SGuanghui Cheng when (!addrAligned || triggerDebugMode || triggerBreakpoint) { 268b0a60050SGuanghui Cheng // NOTE: when addrAligned or trigger fire, do not need to wait tlb actually 269e9092fe2SLemover // check for miss aligned exceptions, tlb exception are checked next cycle for timing 270024ee227SWilliam Wang // if there are exceptions, no need to execute it 271024ee227SWilliam Wang state := s_finish 2724f39c746SYinan Xu out_valid := true.B 273024ee227SWilliam Wang atom_override_xtval := true.B 274024ee227SWilliam Wang }.otherwise { 275ca2f90a6SLemover state := s_pm 276024ee227SWilliam Wang } 277024ee227SWilliam Wang } 278024ee227SWilliam Wang } 279e9092fe2SLemover } 280024ee227SWilliam Wang 281bb76fc1bSYanqin Li val pbmtReg = RegEnable(io.dtlb.resp.bits.pbmt(0), io.dtlb.resp.fire && !io.dtlb.resp.bits.miss) 282ca2f90a6SLemover when (state === s_pm) { 283cba0a7e0SLemover val pmp = WireInit(io.pmpResp) 284bb76fc1bSYanqin Li is_mmio := Pbmt.isIO(pbmtReg) || (Pbmt.isPMA(pbmtReg) && pmp.mmio) 285f9ac118cSHaoyuan Feng 286e9092fe2SLemover // NOTE: only handle load/store exception here, if other exception happens, don't send here 287e9092fe2SLemover val exception_va = exceptionVec(storePageFault) || exceptionVec(loadPageFault) || 288efe8c804Sxuzefan exceptionVec(storeGuestPageFault) || exceptionVec(loadGuestPageFault) || 289e9092fe2SLemover exceptionVec(storeAccessFault) || exceptionVec(loadAccessFault) 29059ef52f3Szhanglinjuan val exception_pa_mmio_nc = pmp.mmio || Pbmt.isIO(pbmtReg) || Pbmt.isNC(pbmtReg) 29159ef52f3Szhanglinjuan val exception_pa = pmp.st || pmp.ld || exception_pa_mmio_nc 292e9092fe2SLemover when (exception_va || exception_pa) { 293ca2f90a6SLemover state := s_finish 2944f39c746SYinan Xu out_valid := true.B 295ca2f90a6SLemover atom_override_xtval := true.B 296ca2f90a6SLemover }.otherwise { 29752180d7eShappy-lx // if sbuffer has been flushed, go to query dcache, otherwise wait for sbuffer. 29852180d7eShappy-lx state := Mux(sbuffer_empty, s_cache_req, s_wait_flush_sbuffer_resp); 299ca2f90a6SLemover } 3000fedb24cSWilliam Wang // update storeAccessFault bit 30159ef52f3Szhanglinjuan exceptionVec(loadAccessFault) := exceptionVec(loadAccessFault) || 30259ef52f3Szhanglinjuan (pmp.ld || exception_pa_mmio_nc) && isLr 30359ef52f3Szhanglinjuan exceptionVec(storeAccessFault) := exceptionVec(storeAccessFault) || pmp.st || 30459ef52f3Szhanglinjuan (pmp.ld || exception_pa_mmio_nc) && !isLr 305ca2f90a6SLemover } 306024ee227SWilliam Wang 30752180d7eShappy-lx when (state === s_wait_flush_sbuffer_resp) { 30852180d7eShappy-lx when (sbuffer_empty) { 309024ee227SWilliam Wang state := s_cache_req 310024ee227SWilliam Wang } 311024ee227SWilliam Wang } 312024ee227SWilliam Wang 31338c29594Szhanglinjuan def genWdataAMO(data: UInt, sizeEncode: UInt): UInt = { 31438c29594Szhanglinjuan LookupTree(sizeEncode(1, 0), List( 31538c29594Szhanglinjuan "b10".U -> Fill(4, data(31, 0)), 31638c29594Szhanglinjuan "b11".U -> Fill(2, data(63, 0)), 31738c29594Szhanglinjuan "b00".U -> data(127, 0) 318024ee227SWilliam Wang )) 31938c29594Szhanglinjuan } 320024ee227SWilliam Wang 32138c29594Szhanglinjuan def genWmaskAMO(addr: UInt, sizeEncode: UInt): UInt = { 32238c29594Szhanglinjuan /** 32338c29594Szhanglinjuan * `MainPipeReq` uses `word_idx` to recognize which 64-bits data bank to operate on. Double-word atomics are 32438c29594Szhanglinjuan * always 8B aligned and quad-word atomics are always 16B aligned except for misaligned exception, therefore 32538c29594Szhanglinjuan * `word_idx` is enough and there is no need to shift according address. Only word atomics needs LSBs of the 32638c29594Szhanglinjuan * address to shift mask inside a 64-bits aligned range. 32738c29594Szhanglinjuan */ 32838c29594Szhanglinjuan LookupTree(sizeEncode(1, 0), List( 32938c29594Szhanglinjuan "b10".U -> (0xf.U << addr(2,0)), // W 33038c29594Szhanglinjuan "b11".U -> 0xff.U, // D 33138c29594Szhanglinjuan "b00".U -> 0xffff.U // Q 33238c29594Szhanglinjuan )) 33338c29594Szhanglinjuan } 334024ee227SWilliam Wang 33538c29594Szhanglinjuan when (state === s_cache_req) { 3364f39c746SYinan Xu when (io.dcache.req.fire) { 337024ee227SWilliam Wang state := s_cache_resp 338024ee227SWilliam Wang } 339024ee227SWilliam Wang } 340024ee227SWilliam Wang 34162cb71fbShappy-lx val dcache_resp_data = Reg(UInt()) 34262cb71fbShappy-lx val dcache_resp_id = Reg(UInt()) 34362cb71fbShappy-lx val dcache_resp_error = Reg(Bool()) 34462cb71fbShappy-lx 345024ee227SWilliam Wang when (state === s_cache_resp) { 34662cb71fbShappy-lx // when not miss 34762cb71fbShappy-lx // everything is OK, simply send response back to sbuffer 34862cb71fbShappy-lx // when miss and not replay 34962cb71fbShappy-lx // wait for missQueue to handling miss and replaying our request 35062cb71fbShappy-lx // when miss and replay 35162cb71fbShappy-lx // req missed and fail to enter missQueue, manually replay it later 35262cb71fbShappy-lx // TODO: add assertions: 35362cb71fbShappy-lx // 1. add a replay delay counter? 35462cb71fbShappy-lx // 2. when req gets into MissQueue, it should not miss any more 355935edac4STang Haojin when (io.dcache.resp.fire) { 35662cb71fbShappy-lx when (io.dcache.resp.bits.miss) { 35762cb71fbShappy-lx when (io.dcache.resp.bits.replay) { 35862cb71fbShappy-lx state := s_cache_req 35962cb71fbShappy-lx } 36062cb71fbShappy-lx }.otherwise { 36162cb71fbShappy-lx dcache_resp_data := io.dcache.resp.bits.data 36262cb71fbShappy-lx dcache_resp_id := io.dcache.resp.bits.id 36362cb71fbShappy-lx dcache_resp_error := io.dcache.resp.bits.error 36462cb71fbShappy-lx state := s_cache_resp_latch 36562cb71fbShappy-lx } 36662cb71fbShappy-lx } 36762cb71fbShappy-lx } 36862cb71fbShappy-lx 36962cb71fbShappy-lx when (state === s_cache_resp_latch) { 37038c29594Szhanglinjuan success := dcache_resp_id 37138c29594Szhanglinjuan val rdataSel = Mux( 37238c29594Szhanglinjuan paddr(2, 0) === 0.U, 37338c29594Szhanglinjuan dcache_resp_data, 37438c29594Szhanglinjuan dcache_resp_data >> 32 37538c29594Szhanglinjuan ) 37638c29594Szhanglinjuan assert(paddr(2, 0) === "b000".U || paddr(2, 0) === "b100".U) 377024ee227SWilliam Wang 378074ad6aaSzhanglinjuan resp_data_wire := Mux( 379074ad6aaSzhanglinjuan isSc, 380074ad6aaSzhanglinjuan dcache_resp_data, 38138c29594Szhanglinjuan LookupTree(uop.fuOpType(1,0), List( 38238c29594Szhanglinjuan "b10".U -> SignExt(rdataSel(31, 0), QuadWordBits), // W 38338c29594Szhanglinjuan "b11".U -> SignExt(rdataSel(63, 0), QuadWordBits), // D 38438c29594Szhanglinjuan "b00".U -> rdataSel // Q 385024ee227SWilliam Wang )) 386074ad6aaSzhanglinjuan ) 387024ee227SWilliam Wang 38862cb71fbShappy-lx when (dcache_resp_error && io.csrCtrl.cache_error_enable) { 389026615fcSWilliam Wang exceptionVec(loadAccessFault) := isLr 390026615fcSWilliam Wang exceptionVec(storeAccessFault) := !isLr 391026615fcSWilliam Wang assert(!exceptionVec(loadAccessFault)) 392026615fcSWilliam Wang assert(!exceptionVec(storeAccessFault)) 393026615fcSWilliam Wang } 394026615fcSWilliam Wang 395f97664b3Swangkaifan resp_data := resp_data_wire 396024ee227SWilliam Wang state := s_finish 3974f39c746SYinan Xu out_valid := true.B 398024ee227SWilliam Wang } 399024ee227SWilliam Wang 40038c29594Szhanglinjuan when (state === s_finish) { 4014f39c746SYinan Xu when (io.out.fire) { 40238c29594Szhanglinjuan when (LSUOpType.isAMOCASQ(uop.fuOpType)) { 40338c29594Szhanglinjuan // enter `s_finish2` to write the 2nd uop back 40438c29594Szhanglinjuan state := s_finish2 40538c29594Szhanglinjuan out_valid := true.B 40638c29594Szhanglinjuan }.otherwise { 40738c29594Szhanglinjuan // otherwise the FSM ends here 40838c29594Szhanglinjuan resetFSM() 40938c29594Szhanglinjuan } 41038c29594Szhanglinjuan } 411024ee227SWilliam Wang } 4124f39c746SYinan Xu 41338c29594Szhanglinjuan when (state === s_finish2) { 41438c29594Szhanglinjuan when (io.out.fire) { 41538c29594Szhanglinjuan resetFSM() 41638c29594Szhanglinjuan } 417024ee227SWilliam Wang } 418024ee227SWilliam Wang 419f4b2089aSYinan Xu when (io.redirect.valid) { 420024ee227SWilliam Wang atom_override_xtval := false.B 421024ee227SWilliam Wang } 4228a5bdd64Swangkaifan 42338c29594Szhanglinjuan def resetFSM(): Unit = { 42438c29594Szhanglinjuan state := s_invalid 42538c29594Szhanglinjuan out_valid := false.B 42638c29594Szhanglinjuan data_valid := false.B 42738c29594Szhanglinjuan stdCnt := 0.U 42838c29594Szhanglinjuan pdest1Valid := false.B 42938c29594Szhanglinjuan pdest2Valid := false.B 43038c29594Szhanglinjuan } 43138c29594Szhanglinjuan 43238c29594Szhanglinjuan /** 43338c29594Szhanglinjuan * IO assignment 43438c29594Szhanglinjuan */ 43538c29594Szhanglinjuan io.exceptionInfo.valid := atom_override_xtval 43638c29594Szhanglinjuan io.exceptionInfo.bits.vaddr := vaddr 43738c29594Szhanglinjuan io.exceptionInfo.bits.gpaddr := gpaddr 43838c29594Szhanglinjuan io.exceptionInfo.bits.isForVSnonLeafPTE := isForVSnonLeafPTE 43938c29594Szhanglinjuan 44038c29594Szhanglinjuan // Send TLB feedback to store issue queue 44138c29594Szhanglinjuan // we send feedback right after we receives request 44238c29594Szhanglinjuan // also, we always treat amo as tlb hit 44338c29594Szhanglinjuan // since we will continue polling tlb all by ourself 44438c29594Szhanglinjuan io.feedbackSlow.valid := GatedValidRegNext(GatedValidRegNext(io.in.valid)) 44538c29594Szhanglinjuan io.feedbackSlow.bits.hit := true.B 44638c29594Szhanglinjuan io.feedbackSlow.bits.robIdx := RegEnable(io.in.bits.uop.robIdx, io.in.valid) 44738c29594Szhanglinjuan io.feedbackSlow.bits.sqIdx := RegEnable(io.in.bits.uop.sqIdx, io.in.valid) 44838c29594Szhanglinjuan io.feedbackSlow.bits.lqIdx := RegEnable(io.in.bits.uop.lqIdx, io.in.valid) 44938c29594Szhanglinjuan io.feedbackSlow.bits.flushState := DontCare 45038c29594Szhanglinjuan io.feedbackSlow.bits.sourceType := DontCare 45138c29594Szhanglinjuan io.feedbackSlow.bits.dataInvalidSqIdx := DontCare 45238c29594Szhanglinjuan 45338c29594Szhanglinjuan // send req to dtlb 45438c29594Szhanglinjuan // keep firing until tlb hit 45538c29594Szhanglinjuan io.dtlb.req.valid := state === s_tlb_and_flush_sbuffer_req 45638c29594Szhanglinjuan io.dtlb.req.bits.vaddr := vaddr 45738c29594Szhanglinjuan io.dtlb.req.bits.fullva := vaddr 45838c29594Szhanglinjuan io.dtlb.req.bits.checkfullva := true.B 45938c29594Szhanglinjuan io.dtlb.resp.ready := true.B 46038c29594Szhanglinjuan io.dtlb.req.bits.cmd := Mux(isLr, TlbCmd.atom_read, TlbCmd.atom_write) 46138c29594Szhanglinjuan io.dtlb.req.bits.debug.pc := uop.pc 46238c29594Szhanglinjuan io.dtlb.req.bits.debug.robIdx := uop.robIdx 46338c29594Szhanglinjuan io.dtlb.req.bits.debug.isFirstIssue := false.B 46438c29594Szhanglinjuan io.out.bits.uop.debugInfo.tlbFirstReqTime := GTimer() // FIXME lyq: it will be always assigned 46538c29594Szhanglinjuan 46638c29594Szhanglinjuan // send req to sbuffer to flush it if it is not empty 46738c29594Szhanglinjuan io.flush_sbuffer.valid := !sbuffer_empty && state === s_tlb_and_flush_sbuffer_req 46838c29594Szhanglinjuan 46938c29594Szhanglinjuan // When is sta issue port ready: 47038c29594Szhanglinjuan // (1) AtomicsUnit is idle, or 47138c29594Szhanglinjuan // (2) For AMOCAS.Q, the second uop with the pdest of the higher bits of rd is not received yet 47238c29594Szhanglinjuan io.in.ready := state === s_invalid || LSUOpType.isAMOCASQ(uop.fuOpType) && (!pdest2Valid || !pdest1Valid) 47338c29594Szhanglinjuan 47438c29594Szhanglinjuan io.out.valid := out_valid && Mux(state === s_finish2, pdest2Valid, pdest1Valid) 47538c29594Szhanglinjuan XSError((state === s_finish || state === s_finish2) =/= out_valid, "out_valid reg error\n") 47638c29594Szhanglinjuan io.out.bits := DontCare 47738c29594Szhanglinjuan io.out.bits.uop := uop 47838c29594Szhanglinjuan io.out.bits.uop.fuType := FuType.mou.U 47938c29594Szhanglinjuan io.out.bits.uop.pdest := Mux(state === s_finish2, pdest2, pdest1) 48038c29594Szhanglinjuan io.out.bits.uop.exceptionVec := exceptionVec 48138c29594Szhanglinjuan io.out.bits.uop.trigger := trigger 48238c29594Szhanglinjuan io.out.bits.data := Mux(state === s_finish2, resp_data >> XLEN, resp_data) 48338c29594Szhanglinjuan io.out.bits.debug.isMMIO := is_mmio 48438c29594Szhanglinjuan io.out.bits.debug.paddr := paddr 48538c29594Szhanglinjuan 48638c29594Szhanglinjuan io.dcache.req.valid := Mux( 48738c29594Szhanglinjuan io.dcache.req.bits.cmd === M_XLR, 48838c29594Szhanglinjuan !io.dcache.block_lr, // block lr to survive in lr storm 48938c29594Szhanglinjuan data_valid // wait until src(1) is ready 49038c29594Szhanglinjuan ) && state === s_cache_req 49138c29594Szhanglinjuan val pipe_req = io.dcache.req.bits 49238c29594Szhanglinjuan pipe_req := DontCare 49338c29594Szhanglinjuan pipe_req.cmd := LookupTree(uop.fuOpType, List( 49438c29594Szhanglinjuan // TODO: optimize this 49538c29594Szhanglinjuan LSUOpType.lr_w -> M_XLR, 49638c29594Szhanglinjuan LSUOpType.sc_w -> M_XSC, 49738c29594Szhanglinjuan LSUOpType.amoswap_w -> M_XA_SWAP, 49838c29594Szhanglinjuan LSUOpType.amoadd_w -> M_XA_ADD, 49938c29594Szhanglinjuan LSUOpType.amoxor_w -> M_XA_XOR, 50038c29594Szhanglinjuan LSUOpType.amoand_w -> M_XA_AND, 50138c29594Szhanglinjuan LSUOpType.amoor_w -> M_XA_OR, 50238c29594Szhanglinjuan LSUOpType.amomin_w -> M_XA_MIN, 50338c29594Szhanglinjuan LSUOpType.amomax_w -> M_XA_MAX, 50438c29594Szhanglinjuan LSUOpType.amominu_w -> M_XA_MINU, 50538c29594Szhanglinjuan LSUOpType.amomaxu_w -> M_XA_MAXU, 50638c29594Szhanglinjuan LSUOpType.amocas_w -> M_XA_CASW, 50738c29594Szhanglinjuan 50838c29594Szhanglinjuan LSUOpType.lr_d -> M_XLR, 50938c29594Szhanglinjuan LSUOpType.sc_d -> M_XSC, 51038c29594Szhanglinjuan LSUOpType.amoswap_d -> M_XA_SWAP, 51138c29594Szhanglinjuan LSUOpType.amoadd_d -> M_XA_ADD, 51238c29594Szhanglinjuan LSUOpType.amoxor_d -> M_XA_XOR, 51338c29594Szhanglinjuan LSUOpType.amoand_d -> M_XA_AND, 51438c29594Szhanglinjuan LSUOpType.amoor_d -> M_XA_OR, 51538c29594Szhanglinjuan LSUOpType.amomin_d -> M_XA_MIN, 51638c29594Szhanglinjuan LSUOpType.amomax_d -> M_XA_MAX, 51738c29594Szhanglinjuan LSUOpType.amominu_d -> M_XA_MINU, 51838c29594Szhanglinjuan LSUOpType.amomaxu_d -> M_XA_MAXU, 51938c29594Szhanglinjuan LSUOpType.amocas_d -> M_XA_CASD, 52038c29594Szhanglinjuan 52138c29594Szhanglinjuan LSUOpType.amocas_q -> M_XA_CASQ 52238c29594Szhanglinjuan )) 52338c29594Szhanglinjuan pipe_req.miss := false.B 52438c29594Szhanglinjuan pipe_req.probe := false.B 52538c29594Szhanglinjuan pipe_req.probe_need_data := false.B 52638c29594Szhanglinjuan pipe_req.source := AMO_SOURCE.U 52738c29594Szhanglinjuan pipe_req.addr := get_block_addr(paddr) 52838c29594Szhanglinjuan pipe_req.vaddr := get_block_addr(vaddr) 52938c29594Szhanglinjuan pipe_req.word_idx := get_word(paddr) 53038c29594Szhanglinjuan pipe_req.amo_data := genWdataAMO(rs2, uop.fuOpType) 53138c29594Szhanglinjuan pipe_req.amo_mask := genWmaskAMO(paddr, uop.fuOpType) 53238c29594Szhanglinjuan pipe_req.amo_cmp := genWdataAMO(rd, uop.fuOpType) 53338c29594Szhanglinjuan 5341545277aSYinan Xu if (env.EnableDifftest) { 5357d45a146SYinan Xu val difftest = DifftestModule(new DiffAtomicEvent) 53638c29594Szhanglinjuan val en = io.dcache.req.fire 5377d45a146SYinan Xu difftest.coreid := io.hartId 5387d45a146SYinan Xu difftest.valid := state === s_cache_resp_latch 53938c29594Szhanglinjuan difftest.addr := RegEnable(paddr, en) 54038c29594Szhanglinjuan difftest.data := RegEnable(io.dcache.req.bits.amo_data.asTypeOf(difftest.data), en) 54138c29594Szhanglinjuan difftest.mask := RegEnable(io.dcache.req.bits.amo_mask, en) 54238c29594Szhanglinjuan difftest.cmp := RegEnable(io.dcache.req.bits.amo_cmp.asTypeOf(difftest.cmp), en) 54338c29594Szhanglinjuan difftest.fuop := RegEnable(uop.fuOpType, en) 54438c29594Szhanglinjuan difftest.out := resp_data_wire.asTypeOf(difftest.out) 5458a5bdd64Swangkaifan } 546e13d224aSYinan Xu 547e13d224aSYinan Xu if (env.EnableDifftest || env.AlwaysBasicDiff) { 548e13d224aSYinan Xu val uop = io.out.bits.uop 5497d45a146SYinan Xu val difftest = DifftestModule(new DiffLrScEvent) 5507d45a146SYinan Xu difftest.coreid := io.hartId 55138c29594Szhanglinjuan difftest.valid := io.out.fire && state === s_finish && isSc 55238c29594Szhanglinjuan difftest.success := success 553e13d224aSYinan Xu } 554024ee227SWilliam Wang} 555