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 319e12e8edScz4eimport xiangshan.mem.Bundles._ 32bb76fc1bSYanqin Liimport xiangshan.cache.mmu.Pbmt 339e12e8edScz4eimport xiangshan.cache.{AtomicWordIO, HasDCacheParameters, MemoryOpConstants} 349e12e8edScz4eimport xiangshan.cache.mmu.{TlbCmd, TlbRequestIO} 359e12e8edScz4eimport 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 63*1592abd1SYan Xu PerfCCT.updateInstPos(io.in.bits.uop.debug_seqNum, PerfCCT.InstPos.AtFU.id.U, io.in.valid, clock, reset) 64*1592abd1SYan Xu 65024ee227SWilliam Wang //------------------------------------------------------- 66024ee227SWilliam Wang // Atomics Memory Accsess FSM 67024ee227SWilliam Wang //------------------------------------------------------- 6838c29594Szhanglinjuan 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) 69024ee227SWilliam Wang val state = RegInit(s_invalid) 704f39c746SYinan Xu val out_valid = RegInit(false.B) 711b7adedcSWilliam Wang val data_valid = RegInit(false.B) 7238c29594Szhanglinjuan 7338c29594Szhanglinjuan val uop = Reg(io.in.bits.uop.cloneType) 7438c29594Szhanglinjuan val isLr = LSUOpType.isLr(uop.fuOpType) 7538c29594Szhanglinjuan val isSc = LSUOpType.isSc(uop.fuOpType) 7638c29594Szhanglinjuan val isAMOCAS = LSUOpType.isAMOCAS(uop.fuOpType) 7738c29594Szhanglinjuan val isNotLr = !isLr 7838c29594Szhanglinjuan val isNotSc = !isSc 7938c29594Szhanglinjuan // AMOCAS.Q needs to write two int registers, therefore backend issues two sta uops for AMOCAS.Q. 8038c29594Szhanglinjuan // `pdest2` is used to record the pdest of the second uop 8138c29594Szhanglinjuan val pdest1, pdest2 = Reg(UInt(PhyRegIdxWidth.W)) 8238c29594Szhanglinjuan val pdest1Valid, pdest2Valid = RegInit(false.B) 8338c29594Szhanglinjuan /** 8438c29594Szhanglinjuan * The # of std uops that an atomic instruction require: 8538c29594Szhanglinjuan * (1) For AMOs (except AMOCAS) and LR/SC, 1 std uop is wanted: X(rs2) with uopIdx = 0 8638c29594Szhanglinjuan * (2) For AMOCAS.W/D, 2 std uops are wanted: X(rd), X(rs2) with uopIdx = 0, 1 8738c29594Szhanglinjuan * (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 8838c29594Szhanglinjuan * stds are not needed for write-back. 8938c29594Szhanglinjuan * 9038c29594Szhanglinjuan * The # of sta uops that an atomic instruction require, also the # of write-back: 9138c29594Szhanglinjuan * (1) For AMOs(except AMOCAS.Q) and LR/SC, 1 sta uop is wanted: X(rs1) with uopIdx = 0 9238c29594Szhanglinjuan * (2) For AMOCAS.Q, 2 sta uop is wanted: X(rs1)*2 with uopIdx = 0, 2 9338c29594Szhanglinjuan */ 9438c29594Szhanglinjuan val rs1, rs2_l, rs2_h, rd_l, rd_h = Reg(UInt(XLEN.W)) 9538c29594Szhanglinjuan val stds = Seq(rd_l, rs2_l, rd_h, rs2_h) 9638c29594Szhanglinjuan val rs2 = Cat(rs2_h, Mux(isAMOCAS, rs2_l, stds.head)) 9738c29594Szhanglinjuan val rd = Cat(rd_h, rd_l) 9838c29594Szhanglinjuan val stdCnt = RegInit(0.U(log2Ceil(stds.length + 1).W)) 9938c29594Szhanglinjuan 1000d045bd0SYinan Xu val exceptionVec = RegInit(0.U.asTypeOf(ExceptionVec())) 101204141efSGuanghui Cheng val trigger = RegInit(TriggerAction.None) 102024ee227SWilliam Wang val atom_override_xtval = RegInit(false.B) 1036fce12d9SWilliam Wang val have_sent_first_tlb_req = RegInit(false.B) 104024ee227SWilliam Wang // paddr after translation 105024ee227SWilliam Wang val paddr = Reg(UInt()) 106d0de7e4aSpeixiaokun val gpaddr = Reg(UInt()) 10738c29594Szhanglinjuan val vaddr = rs1 10838c29594Szhanglinjuan 109cff68e26SWilliam Wang val is_mmio = Reg(Bool()) 110ad415ae0SXiaokun-Pei val isForVSnonLeafPTE = Reg(Bool()) 111f9ac118cSHaoyuan Feng 112024ee227SWilliam Wang // dcache response data 113024ee227SWilliam Wang val resp_data = Reg(UInt()) 114f97664b3Swangkaifan val resp_data_wire = WireInit(0.U) 11538c29594Szhanglinjuan val success = Reg(Bool()) 11652180d7eShappy-lx // sbuffer is empty or not 11752180d7eShappy-lx val sbuffer_empty = io.flush_sbuffer.empty 118024ee227SWilliam Wang 11938c29594Szhanglinjuan // Only the least significant AMOFuOpWidth = 6 bits of fuOpType are used, 12038c29594Szhanglinjuan // therefore the MSBs are reused to identify uopIdx 12138c29594Szhanglinjuan val stdUopIdxs = io.storeDataIn.map(_.bits.uop.fuOpType >> LSUOpType.AMOFuOpWidth) 12238c29594Szhanglinjuan val staUopIdx = io.in.bits.uop.fuOpType >> LSUOpType.AMOFuOpWidth 123024ee227SWilliam Wang 124024ee227SWilliam Wang // assign default value to output signals 125024ee227SWilliam Wang io.in.ready := false.B 126024ee227SWilliam Wang 127024ee227SWilliam Wang io.dcache.req.valid := false.B 128024ee227SWilliam Wang io.dcache.req.bits := DontCare 129024ee227SWilliam Wang 130024ee227SWilliam Wang io.dtlb.req.valid := false.B 131024ee227SWilliam Wang io.dtlb.req.bits := DontCare 132c3b763d0SYinan Xu io.dtlb.req_kill := false.B 1339930e66fSLemover io.dtlb.resp.ready := true.B 134024ee227SWilliam Wang 135024ee227SWilliam Wang io.flush_sbuffer.valid := false.B 136024ee227SWilliam Wang 137024ee227SWilliam Wang when (state === s_invalid) { 1384f39c746SYinan Xu when (io.in.fire) { 13938c29594Szhanglinjuan uop := io.in.bits.uop 14038c29594Szhanglinjuan rs1 := io.in.bits.src_rs1 14152180d7eShappy-lx state := s_tlb_and_flush_sbuffer_req 1426fce12d9SWilliam Wang have_sent_first_tlb_req := false.B 1431b7adedcSWilliam Wang } 14482d348fbSLemover } 14582d348fbSLemover 14638c29594Szhanglinjuan when (io.in.fire) { 14738c29594Szhanglinjuan val pdest = io.in.bits.uop.pdest 14838c29594Szhanglinjuan when (staUopIdx === 0.U) { 14938c29594Szhanglinjuan pdest1Valid := true.B 15038c29594Szhanglinjuan pdest1 := pdest 15138c29594Szhanglinjuan }.elsewhen (staUopIdx === 2.U) { 15238c29594Szhanglinjuan pdest2Valid := true.B 15338c29594Szhanglinjuan pdest2 := pdest 15438c29594Szhanglinjuan }.otherwise { 15538c29594Szhanglinjuan assert(false.B, "unrecognized sta uopIdx") 15638c29594Szhanglinjuan } 1571b7adedcSWilliam Wang } 158024ee227SWilliam Wang 15938c29594Szhanglinjuan stds.zipWithIndex.foreach { case (data, i) => 16038c29594Szhanglinjuan val sels = io.storeDataIn.zip(stdUopIdxs).map { case (in, uopIdx) => 16138c29594Szhanglinjuan val sel = in.fire && uopIdx === i.U 16238c29594Szhanglinjuan when (sel) { data := in.bits.data } 16338c29594Szhanglinjuan sel 16438c29594Szhanglinjuan } 16538c29594Szhanglinjuan OneHot.checkOneHot(sels) 16638c29594Szhanglinjuan } 16738c29594Szhanglinjuan stdCnt := stdCnt + PopCount(io.storeDataIn.map(_.fire)) 16838c29594Szhanglinjuan 16938c29594Szhanglinjuan val StdCntNCAS = 1 // LR/SC and AMO need only 1 src besides rs1 17038c29594Szhanglinjuan val StdCntCASWD = 2 // AMOCAS.W/D needs 2 src regs (rs2 and rd) besides rs1 17138c29594Szhanglinjuan val StdCntCASQ = 4 // AMOCAS.Q needs 4 src regs (rs2, rs2+1, rd, rd+1) besides rs1 17238c29594Szhanglinjuan when (!data_valid) { 17338c29594Szhanglinjuan data_valid := state =/= s_invalid && ( 17438c29594Szhanglinjuan LSUOpType.isAMOCASQ(uop.fuOpType) && stdCnt === StdCntCASQ.U || 17538c29594Szhanglinjuan LSUOpType.isAMOCASWD(uop.fuOpType) && stdCnt === StdCntCASWD.U || 17638c29594Szhanglinjuan !isAMOCAS && stdCnt === StdCntNCAS.U 17738c29594Szhanglinjuan ) 17838c29594Szhanglinjuan } 17938c29594Szhanglinjuan assert(stdCnt <= stds.length.U, "unexpected std") 18038c29594Szhanglinjuan assert(!(Cat(io.storeDataIn.map(_.fire)).orR && data_valid), "atomic unit re-receive data") 181024ee227SWilliam Wang 182204141efSGuanghui Cheng // atomic trigger 183204141efSGuanghui Cheng val csrCtrl = io.csrCtrl 184204141efSGuanghui Cheng val tdata = Reg(Vec(TriggerNum, new MatchTriggerIO)) 185204141efSGuanghui Cheng val tEnableVec = RegInit(VecInit(Seq.fill(TriggerNum)(false.B))) 186204141efSGuanghui Cheng tEnableVec := csrCtrl.mem_trigger.tEnableVec 187204141efSGuanghui Cheng when (csrCtrl.mem_trigger.tUpdate.valid) { 188204141efSGuanghui Cheng tdata(csrCtrl.mem_trigger.tUpdate.bits.addr) := csrCtrl.mem_trigger.tUpdate.bits.tdata 189204141efSGuanghui Cheng } 190204141efSGuanghui Cheng 191204141efSGuanghui Cheng val debugMode = csrCtrl.mem_trigger.debugMode 192204141efSGuanghui Cheng val triggerCanRaiseBpExp = csrCtrl.mem_trigger.triggerCanRaiseBpExp 193204141efSGuanghui Cheng val backendTriggerTimingVec = VecInit(tdata.map(_.timing)) 194204141efSGuanghui Cheng val backendTriggerChainVec = VecInit(tdata.map(_.chain)) 195204141efSGuanghui Cheng val backendTriggerHitVec = WireInit(VecInit(Seq.fill(TriggerNum)(false.B))) 196204141efSGuanghui Cheng val backendTriggerCanFireVec = RegInit(VecInit(Seq.fill(TriggerNum)(false.B))) 197204141efSGuanghui Cheng 19838c29594Szhanglinjuan assert(state === s_invalid || 19938c29594Szhanglinjuan uop.fuOpType(1,0) === "b10".U || 20038c29594Szhanglinjuan uop.fuOpType(1,0) === "b11".U || 20138c29594Szhanglinjuan LSUOpType.isAMOCASQ(uop.fuOpType), 20238c29594Szhanglinjuan "Only word or doubleword or quadword is supported" 20338c29594Szhanglinjuan ) 204204141efSGuanghui Cheng 205204141efSGuanghui Cheng // store trigger 206204141efSGuanghui Cheng val store_hit = Wire(Vec(TriggerNum, Bool())) 207204141efSGuanghui Cheng for (j <- 0 until TriggerNum) { 208204141efSGuanghui Cheng store_hit(j) := !tdata(j).select && !debugMode && isNotLr && TriggerCmp( 209204141efSGuanghui Cheng vaddr, 210204141efSGuanghui Cheng tdata(j).tdata2, 211204141efSGuanghui Cheng tdata(j).matchType, 212204141efSGuanghui Cheng tEnableVec(j) && tdata(j).store 213204141efSGuanghui Cheng ) 214204141efSGuanghui Cheng } 215204141efSGuanghui Cheng // load trigger 216204141efSGuanghui Cheng val load_hit = Wire(Vec(TriggerNum, Bool())) 217204141efSGuanghui Cheng for (j <- 0 until TriggerNum) { 218204141efSGuanghui Cheng load_hit(j) := !tdata(j).select && !debugMode && isNotSc && TriggerCmp( 219204141efSGuanghui Cheng vaddr, 220204141efSGuanghui Cheng tdata(j).tdata2, 221204141efSGuanghui Cheng tdata(j).matchType, 222204141efSGuanghui Cheng tEnableVec(j) && tdata(j).load 223204141efSGuanghui Cheng ) 224204141efSGuanghui Cheng } 225204141efSGuanghui Cheng backendTriggerHitVec := store_hit.zip(load_hit).map { case (sh, lh) => sh || lh } 226204141efSGuanghui Cheng // triggerCanFireVec will update at T+1 22738c29594Szhanglinjuan TriggerCheckCanFire(TriggerNum, backendTriggerCanFireVec, backendTriggerHitVec, 22838c29594Szhanglinjuan backendTriggerTimingVec, backendTriggerChainVec) 229204141efSGuanghui Cheng 230204141efSGuanghui Cheng val actionVec = VecInit(tdata.map(_.action)) 231204141efSGuanghui Cheng val triggerAction = Wire(TriggerAction()) 232204141efSGuanghui Cheng TriggerUtil.triggerActionGen(triggerAction, backendTriggerCanFireVec, actionVec, triggerCanRaiseBpExp) 233b0a60050SGuanghui Cheng val triggerDebugMode = TriggerAction.isDmode(triggerAction) 234b0a60050SGuanghui Cheng val triggerBreakpoint = TriggerAction.isExp(triggerAction) 235204141efSGuanghui Cheng 236024ee227SWilliam Wang // tlb translation, manipulating signals && deal with exception 23752180d7eShappy-lx // at the same time, flush sbuffer 23852180d7eShappy-lx when (state === s_tlb_and_flush_sbuffer_req) { 2396fce12d9SWilliam Wang // do not accept tlb resp in the first cycle 2406fce12d9SWilliam Wang // this limition is for hw prefetcher 2416fce12d9SWilliam Wang // when !have_sent_first_tlb_req, tlb resp may come from hw prefetch 2426fce12d9SWilliam Wang have_sent_first_tlb_req := true.B 2436fce12d9SWilliam Wang 2446fce12d9SWilliam Wang when (io.dtlb.resp.fire && have_sent_first_tlb_req) { 24503efd994Shappy-lx paddr := io.dtlb.resp.bits.paddr(0) 246d0de7e4aSpeixiaokun gpaddr := io.dtlb.resp.bits.gpaddr(0) 247189833a1SHaoyuan Feng vaddr := io.dtlb.resp.bits.fullva 248ad415ae0SXiaokun-Pei isForVSnonLeafPTE := io.dtlb.resp.bits.isForVSnonLeafPTE 249024ee227SWilliam Wang // exception handling 25038c29594Szhanglinjuan val addrAligned = LookupTree(uop.fuOpType(1,0), List( 25138c29594Szhanglinjuan "b10".U -> (vaddr(1,0) === 0.U), // W 25238c29594Szhanglinjuan "b11".U -> (vaddr(2,0) === 0.U), // D 25338c29594Szhanglinjuan "b00".U -> (vaddr(3,0) === 0.U) // Q 254024ee227SWilliam Wang )) 2558c343485SWilliam Wang exceptionVec(loadAddrMisaligned) := !addrAligned && isLr 2568c343485SWilliam Wang exceptionVec(storeAddrMisaligned) := !addrAligned && !isLr 25703efd994Shappy-lx exceptionVec(storePageFault) := io.dtlb.resp.bits.excp(0).pf.st 25803efd994Shappy-lx exceptionVec(loadPageFault) := io.dtlb.resp.bits.excp(0).pf.ld 25903efd994Shappy-lx exceptionVec(storeAccessFault) := io.dtlb.resp.bits.excp(0).af.st 26003efd994Shappy-lx exceptionVec(loadAccessFault) := io.dtlb.resp.bits.excp(0).af.ld 261d0de7e4aSpeixiaokun exceptionVec(storeGuestPageFault) := io.dtlb.resp.bits.excp(0).gpf.st 262d0de7e4aSpeixiaokun exceptionVec(loadGuestPageFault) := io.dtlb.resp.bits.excp(0).gpf.ld 263e9092fe2SLemover 264b0a60050SGuanghui Cheng exceptionVec(breakPoint) := triggerBreakpoint 265204141efSGuanghui Cheng trigger := triggerAction 266204141efSGuanghui Cheng 267e9092fe2SLemover when (!io.dtlb.resp.bits.miss) { 2688744445eSMaxpicca-Li io.out.bits.uop.debugInfo.tlbRespTime := GTimer() 269b0a60050SGuanghui Cheng when (!addrAligned || triggerDebugMode || triggerBreakpoint) { 270b0a60050SGuanghui Cheng // NOTE: when addrAligned or trigger fire, do not need to wait tlb actually 271e9092fe2SLemover // check for miss aligned exceptions, tlb exception are checked next cycle for timing 272024ee227SWilliam Wang // if there are exceptions, no need to execute it 273024ee227SWilliam Wang state := s_finish 2744f39c746SYinan Xu out_valid := true.B 275024ee227SWilliam Wang atom_override_xtval := true.B 276024ee227SWilliam Wang }.otherwise { 277ca2f90a6SLemover state := s_pm 278024ee227SWilliam Wang } 279024ee227SWilliam Wang } 280024ee227SWilliam Wang } 281e9092fe2SLemover } 282024ee227SWilliam Wang 283bb76fc1bSYanqin Li val pbmtReg = RegEnable(io.dtlb.resp.bits.pbmt(0), io.dtlb.resp.fire && !io.dtlb.resp.bits.miss) 284ca2f90a6SLemover when (state === s_pm) { 285cba0a7e0SLemover val pmp = WireInit(io.pmpResp) 286bb76fc1bSYanqin Li is_mmio := Pbmt.isIO(pbmtReg) || (Pbmt.isPMA(pbmtReg) && pmp.mmio) 287f9ac118cSHaoyuan Feng 288e9092fe2SLemover // NOTE: only handle load/store exception here, if other exception happens, don't send here 289e9092fe2SLemover val exception_va = exceptionVec(storePageFault) || exceptionVec(loadPageFault) || 290efe8c804Sxuzefan exceptionVec(storeGuestPageFault) || exceptionVec(loadGuestPageFault) || 291e9092fe2SLemover exceptionVec(storeAccessFault) || exceptionVec(loadAccessFault) 29259ef52f3Szhanglinjuan val exception_pa_mmio_nc = pmp.mmio || Pbmt.isIO(pbmtReg) || Pbmt.isNC(pbmtReg) 29359ef52f3Szhanglinjuan val exception_pa = pmp.st || pmp.ld || exception_pa_mmio_nc 294e9092fe2SLemover when (exception_va || exception_pa) { 295ca2f90a6SLemover state := s_finish 2964f39c746SYinan Xu out_valid := true.B 297ca2f90a6SLemover atom_override_xtval := true.B 298ca2f90a6SLemover }.otherwise { 29952180d7eShappy-lx // if sbuffer has been flushed, go to query dcache, otherwise wait for sbuffer. 30052180d7eShappy-lx state := Mux(sbuffer_empty, s_cache_req, s_wait_flush_sbuffer_resp); 301ca2f90a6SLemover } 3020fedb24cSWilliam Wang // update storeAccessFault bit 30359ef52f3Szhanglinjuan exceptionVec(loadAccessFault) := exceptionVec(loadAccessFault) || 30459ef52f3Szhanglinjuan (pmp.ld || exception_pa_mmio_nc) && isLr 30559ef52f3Szhanglinjuan exceptionVec(storeAccessFault) := exceptionVec(storeAccessFault) || pmp.st || 30659ef52f3Szhanglinjuan (pmp.ld || exception_pa_mmio_nc) && !isLr 307ca2f90a6SLemover } 308024ee227SWilliam Wang 30952180d7eShappy-lx when (state === s_wait_flush_sbuffer_resp) { 31052180d7eShappy-lx when (sbuffer_empty) { 311024ee227SWilliam Wang state := s_cache_req 312024ee227SWilliam Wang } 313024ee227SWilliam Wang } 314024ee227SWilliam Wang 31538c29594Szhanglinjuan def genWdataAMO(data: UInt, sizeEncode: UInt): UInt = { 31638c29594Szhanglinjuan LookupTree(sizeEncode(1, 0), List( 31738c29594Szhanglinjuan "b10".U -> Fill(4, data(31, 0)), 31838c29594Szhanglinjuan "b11".U -> Fill(2, data(63, 0)), 31938c29594Szhanglinjuan "b00".U -> data(127, 0) 320024ee227SWilliam Wang )) 32138c29594Szhanglinjuan } 322024ee227SWilliam Wang 32338c29594Szhanglinjuan def genWmaskAMO(addr: UInt, sizeEncode: UInt): UInt = { 32438c29594Szhanglinjuan /** 32538c29594Szhanglinjuan * `MainPipeReq` uses `word_idx` to recognize which 64-bits data bank to operate on. Double-word atomics are 32638c29594Szhanglinjuan * always 8B aligned and quad-word atomics are always 16B aligned except for misaligned exception, therefore 32738c29594Szhanglinjuan * `word_idx` is enough and there is no need to shift according address. Only word atomics needs LSBs of the 32838c29594Szhanglinjuan * address to shift mask inside a 64-bits aligned range. 32938c29594Szhanglinjuan */ 33038c29594Szhanglinjuan LookupTree(sizeEncode(1, 0), List( 33138c29594Szhanglinjuan "b10".U -> (0xf.U << addr(2,0)), // W 33238c29594Szhanglinjuan "b11".U -> 0xff.U, // D 33338c29594Szhanglinjuan "b00".U -> 0xffff.U // Q 33438c29594Szhanglinjuan )) 33538c29594Szhanglinjuan } 336024ee227SWilliam Wang 33738c29594Szhanglinjuan when (state === s_cache_req) { 3384f39c746SYinan Xu when (io.dcache.req.fire) { 339024ee227SWilliam Wang state := s_cache_resp 340024ee227SWilliam Wang } 341024ee227SWilliam Wang } 342024ee227SWilliam Wang 34362cb71fbShappy-lx val dcache_resp_data = Reg(UInt()) 34462cb71fbShappy-lx val dcache_resp_id = Reg(UInt()) 34562cb71fbShappy-lx val dcache_resp_error = Reg(Bool()) 34662cb71fbShappy-lx 347024ee227SWilliam Wang when (state === s_cache_resp) { 34862cb71fbShappy-lx // when not miss 34962cb71fbShappy-lx // everything is OK, simply send response back to sbuffer 35062cb71fbShappy-lx // when miss and not replay 35162cb71fbShappy-lx // wait for missQueue to handling miss and replaying our request 35262cb71fbShappy-lx // when miss and replay 35362cb71fbShappy-lx // req missed and fail to enter missQueue, manually replay it later 35462cb71fbShappy-lx // TODO: add assertions: 35562cb71fbShappy-lx // 1. add a replay delay counter? 35662cb71fbShappy-lx // 2. when req gets into MissQueue, it should not miss any more 357935edac4STang Haojin when (io.dcache.resp.fire) { 35862cb71fbShappy-lx when (io.dcache.resp.bits.miss) { 35962cb71fbShappy-lx when (io.dcache.resp.bits.replay) { 36062cb71fbShappy-lx state := s_cache_req 36162cb71fbShappy-lx } 36262cb71fbShappy-lx }.otherwise { 36362cb71fbShappy-lx dcache_resp_data := io.dcache.resp.bits.data 36462cb71fbShappy-lx dcache_resp_id := io.dcache.resp.bits.id 36562cb71fbShappy-lx dcache_resp_error := io.dcache.resp.bits.error 36662cb71fbShappy-lx state := s_cache_resp_latch 36762cb71fbShappy-lx } 36862cb71fbShappy-lx } 36962cb71fbShappy-lx } 37062cb71fbShappy-lx 37162cb71fbShappy-lx when (state === s_cache_resp_latch) { 37238c29594Szhanglinjuan success := dcache_resp_id 37338c29594Szhanglinjuan val rdataSel = Mux( 37438c29594Szhanglinjuan paddr(2, 0) === 0.U, 37538c29594Szhanglinjuan dcache_resp_data, 37638c29594Szhanglinjuan dcache_resp_data >> 32 37738c29594Szhanglinjuan ) 37838c29594Szhanglinjuan assert(paddr(2, 0) === "b000".U || paddr(2, 0) === "b100".U) 379024ee227SWilliam Wang 380074ad6aaSzhanglinjuan resp_data_wire := Mux( 381074ad6aaSzhanglinjuan isSc, 382074ad6aaSzhanglinjuan dcache_resp_data, 38338c29594Szhanglinjuan LookupTree(uop.fuOpType(1,0), List( 38438c29594Szhanglinjuan "b10".U -> SignExt(rdataSel(31, 0), QuadWordBits), // W 38538c29594Szhanglinjuan "b11".U -> SignExt(rdataSel(63, 0), QuadWordBits), // D 38638c29594Szhanglinjuan "b00".U -> rdataSel // Q 387024ee227SWilliam Wang )) 388074ad6aaSzhanglinjuan ) 389024ee227SWilliam Wang 39062cb71fbShappy-lx when (dcache_resp_error && io.csrCtrl.cache_error_enable) { 391026615fcSWilliam Wang exceptionVec(loadAccessFault) := isLr 392026615fcSWilliam Wang exceptionVec(storeAccessFault) := !isLr 393026615fcSWilliam Wang assert(!exceptionVec(loadAccessFault)) 394026615fcSWilliam Wang assert(!exceptionVec(storeAccessFault)) 395026615fcSWilliam Wang } 396026615fcSWilliam Wang 397f97664b3Swangkaifan resp_data := resp_data_wire 398024ee227SWilliam Wang state := s_finish 3994f39c746SYinan Xu out_valid := true.B 400024ee227SWilliam Wang } 401024ee227SWilliam Wang 40238c29594Szhanglinjuan when (state === s_finish) { 4034f39c746SYinan Xu when (io.out.fire) { 40438c29594Szhanglinjuan when (LSUOpType.isAMOCASQ(uop.fuOpType)) { 40538c29594Szhanglinjuan // enter `s_finish2` to write the 2nd uop back 40638c29594Szhanglinjuan state := s_finish2 40738c29594Szhanglinjuan out_valid := true.B 40838c29594Szhanglinjuan }.otherwise { 40938c29594Szhanglinjuan // otherwise the FSM ends here 41038c29594Szhanglinjuan resetFSM() 41138c29594Szhanglinjuan } 41238c29594Szhanglinjuan } 413024ee227SWilliam Wang } 4144f39c746SYinan Xu 41538c29594Szhanglinjuan when (state === s_finish2) { 41638c29594Szhanglinjuan when (io.out.fire) { 41738c29594Szhanglinjuan resetFSM() 41838c29594Szhanglinjuan } 419024ee227SWilliam Wang } 420024ee227SWilliam Wang 421f4b2089aSYinan Xu when (io.redirect.valid) { 422024ee227SWilliam Wang atom_override_xtval := false.B 423024ee227SWilliam Wang } 4248a5bdd64Swangkaifan 42538c29594Szhanglinjuan def resetFSM(): Unit = { 42638c29594Szhanglinjuan state := s_invalid 42738c29594Szhanglinjuan out_valid := false.B 42838c29594Szhanglinjuan data_valid := false.B 42938c29594Szhanglinjuan stdCnt := 0.U 43038c29594Szhanglinjuan pdest1Valid := false.B 43138c29594Szhanglinjuan pdest2Valid := false.B 43238c29594Szhanglinjuan } 43338c29594Szhanglinjuan 43438c29594Szhanglinjuan /** 43538c29594Szhanglinjuan * IO assignment 43638c29594Szhanglinjuan */ 43738c29594Szhanglinjuan io.exceptionInfo.valid := atom_override_xtval 43838c29594Szhanglinjuan io.exceptionInfo.bits.vaddr := vaddr 43938c29594Szhanglinjuan io.exceptionInfo.bits.gpaddr := gpaddr 44038c29594Szhanglinjuan io.exceptionInfo.bits.isForVSnonLeafPTE := isForVSnonLeafPTE 44138c29594Szhanglinjuan 44238c29594Szhanglinjuan // Send TLB feedback to store issue queue 44338c29594Szhanglinjuan // we send feedback right after we receives request 44438c29594Szhanglinjuan // also, we always treat amo as tlb hit 44538c29594Szhanglinjuan // since we will continue polling tlb all by ourself 44638c29594Szhanglinjuan io.feedbackSlow.valid := GatedValidRegNext(GatedValidRegNext(io.in.valid)) 44738c29594Szhanglinjuan io.feedbackSlow.bits.hit := true.B 44838c29594Szhanglinjuan io.feedbackSlow.bits.robIdx := RegEnable(io.in.bits.uop.robIdx, io.in.valid) 44938c29594Szhanglinjuan io.feedbackSlow.bits.sqIdx := RegEnable(io.in.bits.uop.sqIdx, io.in.valid) 45038c29594Szhanglinjuan io.feedbackSlow.bits.lqIdx := RegEnable(io.in.bits.uop.lqIdx, io.in.valid) 45138c29594Szhanglinjuan io.feedbackSlow.bits.flushState := DontCare 45238c29594Szhanglinjuan io.feedbackSlow.bits.sourceType := DontCare 45338c29594Szhanglinjuan io.feedbackSlow.bits.dataInvalidSqIdx := DontCare 45438c29594Szhanglinjuan 45538c29594Szhanglinjuan // send req to dtlb 45638c29594Szhanglinjuan // keep firing until tlb hit 45738c29594Szhanglinjuan io.dtlb.req.valid := state === s_tlb_and_flush_sbuffer_req 45838c29594Szhanglinjuan io.dtlb.req.bits.vaddr := vaddr 45938c29594Szhanglinjuan io.dtlb.req.bits.fullva := vaddr 46038c29594Szhanglinjuan io.dtlb.req.bits.checkfullva := true.B 46138c29594Szhanglinjuan io.dtlb.resp.ready := true.B 46238c29594Szhanglinjuan io.dtlb.req.bits.cmd := Mux(isLr, TlbCmd.atom_read, TlbCmd.atom_write) 46338c29594Szhanglinjuan io.dtlb.req.bits.debug.pc := uop.pc 46438c29594Szhanglinjuan io.dtlb.req.bits.debug.robIdx := uop.robIdx 46538c29594Szhanglinjuan io.dtlb.req.bits.debug.isFirstIssue := false.B 46638c29594Szhanglinjuan io.out.bits.uop.debugInfo.tlbFirstReqTime := GTimer() // FIXME lyq: it will be always assigned 46738c29594Szhanglinjuan 46838c29594Szhanglinjuan // send req to sbuffer to flush it if it is not empty 46917b54df0Szhanglinjuan io.flush_sbuffer.valid := !sbuffer_empty && ( 47017b54df0Szhanglinjuan state === s_tlb_and_flush_sbuffer_req || 47117b54df0Szhanglinjuan state === s_pm || 47217b54df0Szhanglinjuan state === s_wait_flush_sbuffer_resp 47317b54df0Szhanglinjuan ) 47438c29594Szhanglinjuan 47538c29594Szhanglinjuan // When is sta issue port ready: 47638c29594Szhanglinjuan // (1) AtomicsUnit is idle, or 47738c29594Szhanglinjuan // (2) For AMOCAS.Q, the second uop with the pdest of the higher bits of rd is not received yet 47838c29594Szhanglinjuan io.in.ready := state === s_invalid || LSUOpType.isAMOCASQ(uop.fuOpType) && (!pdest2Valid || !pdest1Valid) 47938c29594Szhanglinjuan 48038c29594Szhanglinjuan io.out.valid := out_valid && Mux(state === s_finish2, pdest2Valid, pdest1Valid) 48138c29594Szhanglinjuan XSError((state === s_finish || state === s_finish2) =/= out_valid, "out_valid reg error\n") 48238c29594Szhanglinjuan io.out.bits := DontCare 48338c29594Szhanglinjuan io.out.bits.uop := uop 48438c29594Szhanglinjuan io.out.bits.uop.fuType := FuType.mou.U 48538c29594Szhanglinjuan io.out.bits.uop.pdest := Mux(state === s_finish2, pdest2, pdest1) 48638c29594Szhanglinjuan io.out.bits.uop.exceptionVec := exceptionVec 48738c29594Szhanglinjuan io.out.bits.uop.trigger := trigger 48838c29594Szhanglinjuan io.out.bits.data := Mux(state === s_finish2, resp_data >> XLEN, resp_data) 48938c29594Szhanglinjuan io.out.bits.debug.isMMIO := is_mmio 49038c29594Szhanglinjuan io.out.bits.debug.paddr := paddr 49138c29594Szhanglinjuan 49238c29594Szhanglinjuan io.dcache.req.valid := Mux( 49338c29594Szhanglinjuan io.dcache.req.bits.cmd === M_XLR, 49438c29594Szhanglinjuan !io.dcache.block_lr, // block lr to survive in lr storm 49538c29594Szhanglinjuan data_valid // wait until src(1) is ready 49638c29594Szhanglinjuan ) && state === s_cache_req 49738c29594Szhanglinjuan val pipe_req = io.dcache.req.bits 49838c29594Szhanglinjuan pipe_req := DontCare 49938c29594Szhanglinjuan pipe_req.cmd := LookupTree(uop.fuOpType, List( 50038c29594Szhanglinjuan // TODO: optimize this 50138c29594Szhanglinjuan LSUOpType.lr_w -> M_XLR, 50238c29594Szhanglinjuan LSUOpType.sc_w -> M_XSC, 50338c29594Szhanglinjuan LSUOpType.amoswap_w -> M_XA_SWAP, 50438c29594Szhanglinjuan LSUOpType.amoadd_w -> M_XA_ADD, 50538c29594Szhanglinjuan LSUOpType.amoxor_w -> M_XA_XOR, 50638c29594Szhanglinjuan LSUOpType.amoand_w -> M_XA_AND, 50738c29594Szhanglinjuan LSUOpType.amoor_w -> M_XA_OR, 50838c29594Szhanglinjuan LSUOpType.amomin_w -> M_XA_MIN, 50938c29594Szhanglinjuan LSUOpType.amomax_w -> M_XA_MAX, 51038c29594Szhanglinjuan LSUOpType.amominu_w -> M_XA_MINU, 51138c29594Szhanglinjuan LSUOpType.amomaxu_w -> M_XA_MAXU, 51238c29594Szhanglinjuan LSUOpType.amocas_w -> M_XA_CASW, 51338c29594Szhanglinjuan 51438c29594Szhanglinjuan LSUOpType.lr_d -> M_XLR, 51538c29594Szhanglinjuan LSUOpType.sc_d -> M_XSC, 51638c29594Szhanglinjuan LSUOpType.amoswap_d -> M_XA_SWAP, 51738c29594Szhanglinjuan LSUOpType.amoadd_d -> M_XA_ADD, 51838c29594Szhanglinjuan LSUOpType.amoxor_d -> M_XA_XOR, 51938c29594Szhanglinjuan LSUOpType.amoand_d -> M_XA_AND, 52038c29594Szhanglinjuan LSUOpType.amoor_d -> M_XA_OR, 52138c29594Szhanglinjuan LSUOpType.amomin_d -> M_XA_MIN, 52238c29594Szhanglinjuan LSUOpType.amomax_d -> M_XA_MAX, 52338c29594Szhanglinjuan LSUOpType.amominu_d -> M_XA_MINU, 52438c29594Szhanglinjuan LSUOpType.amomaxu_d -> M_XA_MAXU, 52538c29594Szhanglinjuan LSUOpType.amocas_d -> M_XA_CASD, 52638c29594Szhanglinjuan 52738c29594Szhanglinjuan LSUOpType.amocas_q -> M_XA_CASQ 52838c29594Szhanglinjuan )) 52938c29594Szhanglinjuan pipe_req.miss := false.B 53038c29594Szhanglinjuan pipe_req.probe := false.B 53138c29594Szhanglinjuan pipe_req.probe_need_data := false.B 53238c29594Szhanglinjuan pipe_req.source := AMO_SOURCE.U 53338c29594Szhanglinjuan pipe_req.addr := get_block_addr(paddr) 53438c29594Szhanglinjuan pipe_req.vaddr := get_block_addr(vaddr) 53538c29594Szhanglinjuan pipe_req.word_idx := get_word(paddr) 53638c29594Szhanglinjuan pipe_req.amo_data := genWdataAMO(rs2, uop.fuOpType) 53738c29594Szhanglinjuan pipe_req.amo_mask := genWmaskAMO(paddr, uop.fuOpType) 53838c29594Szhanglinjuan pipe_req.amo_cmp := genWdataAMO(rd, uop.fuOpType) 53938c29594Szhanglinjuan 5401545277aSYinan Xu if (env.EnableDifftest) { 5417d45a146SYinan Xu val difftest = DifftestModule(new DiffAtomicEvent) 54238c29594Szhanglinjuan val en = io.dcache.req.fire 5437d45a146SYinan Xu difftest.coreid := io.hartId 5447d45a146SYinan Xu difftest.valid := state === s_cache_resp_latch 54538c29594Szhanglinjuan difftest.addr := RegEnable(paddr, en) 54638c29594Szhanglinjuan difftest.data := RegEnable(io.dcache.req.bits.amo_data.asTypeOf(difftest.data), en) 54738c29594Szhanglinjuan difftest.mask := RegEnable(io.dcache.req.bits.amo_mask, en) 54838c29594Szhanglinjuan difftest.cmp := RegEnable(io.dcache.req.bits.amo_cmp.asTypeOf(difftest.cmp), en) 54938c29594Szhanglinjuan difftest.fuop := RegEnable(uop.fuOpType, en) 55038c29594Szhanglinjuan difftest.out := resp_data_wire.asTypeOf(difftest.out) 5518a5bdd64Swangkaifan } 552e13d224aSYinan Xu 553e13d224aSYinan Xu if (env.EnableDifftest || env.AlwaysBasicDiff) { 554e13d224aSYinan Xu val uop = io.out.bits.uop 5557d45a146SYinan Xu val difftest = DifftestModule(new DiffLrScEvent) 5567d45a146SYinan Xu difftest.coreid := io.hartId 55738c29594Szhanglinjuan difftest.valid := io.out.fire && state === s_finish && isSc 55838c29594Szhanglinjuan difftest.success := success 559e13d224aSYinan Xu } 560024ee227SWilliam Wang} 561