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._ 253b739f49SXuan Huimport xiangshan.cache.{AtomicWordIO, HasDCacheParameters, MemoryOpConstants} 26ca2f90a6SLemoverimport xiangshan.cache.mmu.{TlbCmd, TlbRequestIO} 272225d46eSJiawei Linimport difftest._ 286ab6918fSYinan Xuimport xiangshan.ExceptionNO._ 29ca2f90a6SLemoverimport xiangshan.backend.fu.PMPRespBundle 30e7ab4635SHuijin Liimport xiangshan.backend.fu.FuType 31730cfbc0SXuan Huimport xiangshan.backend.Bundles.{MemExuInput, MemExuOutput} 327e0f64b0SGuanghui Chengimport xiangshan.backend.fu.NewCSR.TriggerUtil 33f7af4c74Schengguanghuiimport xiangshan.backend.fu.util.SdtrigExt 34bb76fc1bSYanqin Liimport xiangshan.cache.mmu.Pbmt 35024ee227SWilliam Wang 36f7af4c74Schengguanghuiclass AtomicsUnit(implicit p: Parameters) extends XSModule 37f7af4c74Schengguanghui with MemoryOpConstants 38f7af4c74Schengguanghui with HasDCacheParameters 39f7af4c74Schengguanghui with SdtrigExt{ 4038c29594Szhanglinjuan 4138c29594Szhanglinjuan val StdCnt = backendParams.StdCnt 4238c29594Szhanglinjuan 43024ee227SWilliam Wang val io = IO(new Bundle() { 44f57f7f2aSYangyu Chen val hartId = Input(UInt(hartIdLen.W)) 453b739f49SXuan Hu val in = Flipped(Decoupled(new MemExuInput)) 4638c29594Szhanglinjuan val storeDataIn = Flipped(Vec(StdCnt, Valid(new MemExuOutput))) 473b739f49SXuan Hu val out = Decoupled(new MemExuOutput) 486786cfb7SWilliam Wang val dcache = new AtomicWordIO 4903efd994Shappy-lx val dtlb = new TlbRequestIO(2) 50ca2f90a6SLemover val pmpResp = Flipped(new PMPRespBundle()) 51024ee227SWilliam Wang val flush_sbuffer = new SbufferFlushBundle 52d87b76aaSWilliam Wang val feedbackSlow = ValidIO(new RSFeedback) 53024ee227SWilliam Wang val redirect = Flipped(ValidIO(new Redirect)) 54ad415ae0SXiaokun-Pei val exceptionInfo = ValidIO(new Bundle { 55db6cfb5aSHaoyuan Feng val vaddr = UInt(XLEN.W) 56db6cfb5aSHaoyuan Feng val gpaddr = UInt(XLEN.W) 57ad415ae0SXiaokun-Pei val isForVSnonLeafPTE = Bool() 58d0de7e4aSpeixiaokun }) 59026615fcSWilliam Wang val csrCtrl = Flipped(new CustomCSRCtrlIO) 60024ee227SWilliam Wang }) 61024ee227SWilliam Wang 62024ee227SWilliam Wang //------------------------------------------------------- 63024ee227SWilliam Wang // Atomics Memory Accsess FSM 64024ee227SWilliam Wang //------------------------------------------------------- 6538c29594Szhanglinjuan 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) 66024ee227SWilliam Wang val state = RegInit(s_invalid) 674f39c746SYinan Xu val out_valid = RegInit(false.B) 681b7adedcSWilliam Wang val data_valid = RegInit(false.B) 6938c29594Szhanglinjuan 7038c29594Szhanglinjuan val uop = Reg(io.in.bits.uop.cloneType) 7138c29594Szhanglinjuan val isLr = LSUOpType.isLr(uop.fuOpType) 7238c29594Szhanglinjuan val isSc = LSUOpType.isSc(uop.fuOpType) 7338c29594Szhanglinjuan val isAMOCAS = LSUOpType.isAMOCAS(uop.fuOpType) 7438c29594Szhanglinjuan val isNotLr = !isLr 7538c29594Szhanglinjuan val isNotSc = !isSc 7638c29594Szhanglinjuan // AMOCAS.Q needs to write two int registers, therefore backend issues two sta uops for AMOCAS.Q. 7738c29594Szhanglinjuan // `pdest2` is used to record the pdest of the second uop 7838c29594Szhanglinjuan val pdest1, pdest2 = Reg(UInt(PhyRegIdxWidth.W)) 7938c29594Szhanglinjuan val pdest1Valid, pdest2Valid = RegInit(false.B) 8038c29594Szhanglinjuan /** 8138c29594Szhanglinjuan * The # of std uops that an atomic instruction require: 8238c29594Szhanglinjuan * (1) For AMOs (except AMOCAS) and LR/SC, 1 std uop is wanted: X(rs2) with uopIdx = 0 8338c29594Szhanglinjuan * (2) For AMOCAS.W/D, 2 std uops are wanted: X(rd), X(rs2) with uopIdx = 0, 1 8438c29594Szhanglinjuan * (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 8538c29594Szhanglinjuan * stds are not needed for write-back. 8638c29594Szhanglinjuan * 8738c29594Szhanglinjuan * The # of sta uops that an atomic instruction require, also the # of write-back: 8838c29594Szhanglinjuan * (1) For AMOs(except AMOCAS.Q) and LR/SC, 1 sta uop is wanted: X(rs1) with uopIdx = 0 8938c29594Szhanglinjuan * (2) For AMOCAS.Q, 2 sta uop is wanted: X(rs1)*2 with uopIdx = 0, 2 9038c29594Szhanglinjuan */ 9138c29594Szhanglinjuan val rs1, rs2_l, rs2_h, rd_l, rd_h = Reg(UInt(XLEN.W)) 9238c29594Szhanglinjuan val stds = Seq(rd_l, rs2_l, rd_h, rs2_h) 9338c29594Szhanglinjuan val rs2 = Cat(rs2_h, Mux(isAMOCAS, rs2_l, stds.head)) 9438c29594Szhanglinjuan val rd = Cat(rd_h, rd_l) 9538c29594Szhanglinjuan val stdCnt = RegInit(0.U(log2Ceil(stds.length + 1).W)) 9638c29594Szhanglinjuan 970d045bd0SYinan Xu val exceptionVec = RegInit(0.U.asTypeOf(ExceptionVec())) 98204141efSGuanghui Cheng val trigger = RegInit(TriggerAction.None) 99024ee227SWilliam Wang val atom_override_xtval = RegInit(false.B) 1006fce12d9SWilliam Wang val have_sent_first_tlb_req = RegInit(false.B) 101024ee227SWilliam Wang // paddr after translation 102024ee227SWilliam Wang val paddr = Reg(UInt()) 103d0de7e4aSpeixiaokun val gpaddr = Reg(UInt()) 10438c29594Szhanglinjuan val vaddr = rs1 10538c29594Szhanglinjuan 106cff68e26SWilliam Wang val is_mmio = Reg(Bool()) 107ad415ae0SXiaokun-Pei val isForVSnonLeafPTE = Reg(Bool()) 108f9ac118cSHaoyuan Feng 109024ee227SWilliam Wang // dcache response data 110024ee227SWilliam Wang val resp_data = Reg(UInt()) 111f97664b3Swangkaifan val resp_data_wire = WireInit(0.U) 11238c29594Szhanglinjuan val success = Reg(Bool()) 11352180d7eShappy-lx // sbuffer is empty or not 11452180d7eShappy-lx val sbuffer_empty = io.flush_sbuffer.empty 115024ee227SWilliam Wang 11638c29594Szhanglinjuan // Only the least significant AMOFuOpWidth = 6 bits of fuOpType are used, 11738c29594Szhanglinjuan // therefore the MSBs are reused to identify uopIdx 11838c29594Szhanglinjuan val stdUopIdxs = io.storeDataIn.map(_.bits.uop.fuOpType >> LSUOpType.AMOFuOpWidth) 11938c29594Szhanglinjuan val staUopIdx = io.in.bits.uop.fuOpType >> LSUOpType.AMOFuOpWidth 120024ee227SWilliam Wang 121024ee227SWilliam Wang // assign default value to output signals 122024ee227SWilliam Wang io.in.ready := false.B 123024ee227SWilliam Wang 124024ee227SWilliam Wang io.dcache.req.valid := false.B 125024ee227SWilliam Wang io.dcache.req.bits := DontCare 126024ee227SWilliam Wang 127024ee227SWilliam Wang io.dtlb.req.valid := false.B 128024ee227SWilliam Wang io.dtlb.req.bits := DontCare 129c3b763d0SYinan Xu io.dtlb.req_kill := false.B 1309930e66fSLemover io.dtlb.resp.ready := true.B 131024ee227SWilliam Wang 132024ee227SWilliam Wang io.flush_sbuffer.valid := false.B 133024ee227SWilliam Wang 134024ee227SWilliam Wang when (state === s_invalid) { 1354f39c746SYinan Xu when (io.in.fire) { 13638c29594Szhanglinjuan uop := io.in.bits.uop 13738c29594Szhanglinjuan rs1 := io.in.bits.src_rs1 13852180d7eShappy-lx state := s_tlb_and_flush_sbuffer_req 1396fce12d9SWilliam Wang have_sent_first_tlb_req := false.B 1401b7adedcSWilliam Wang } 14182d348fbSLemover } 14282d348fbSLemover 14338c29594Szhanglinjuan when (io.in.fire) { 14438c29594Szhanglinjuan val pdest = io.in.bits.uop.pdest 14538c29594Szhanglinjuan when (staUopIdx === 0.U) { 14638c29594Szhanglinjuan pdest1Valid := true.B 14738c29594Szhanglinjuan pdest1 := pdest 14838c29594Szhanglinjuan }.elsewhen (staUopIdx === 2.U) { 14938c29594Szhanglinjuan pdest2Valid := true.B 15038c29594Szhanglinjuan pdest2 := pdest 15138c29594Szhanglinjuan }.otherwise { 15238c29594Szhanglinjuan assert(false.B, "unrecognized sta uopIdx") 15338c29594Szhanglinjuan } 1541b7adedcSWilliam Wang } 155024ee227SWilliam Wang 15638c29594Szhanglinjuan stds.zipWithIndex.foreach { case (data, i) => 15738c29594Szhanglinjuan val sels = io.storeDataIn.zip(stdUopIdxs).map { case (in, uopIdx) => 15838c29594Szhanglinjuan val sel = in.fire && uopIdx === i.U 15938c29594Szhanglinjuan when (sel) { data := in.bits.data } 16038c29594Szhanglinjuan sel 16138c29594Szhanglinjuan } 16238c29594Szhanglinjuan OneHot.checkOneHot(sels) 16338c29594Szhanglinjuan } 16438c29594Szhanglinjuan stdCnt := stdCnt + PopCount(io.storeDataIn.map(_.fire)) 16538c29594Szhanglinjuan 16638c29594Szhanglinjuan val StdCntNCAS = 1 // LR/SC and AMO need only 1 src besides rs1 16738c29594Szhanglinjuan val StdCntCASWD = 2 // AMOCAS.W/D needs 2 src regs (rs2 and rd) besides rs1 16838c29594Szhanglinjuan val StdCntCASQ = 4 // AMOCAS.Q needs 4 src regs (rs2, rs2+1, rd, rd+1) besides rs1 16938c29594Szhanglinjuan when (!data_valid) { 17038c29594Szhanglinjuan data_valid := state =/= s_invalid && ( 17138c29594Szhanglinjuan LSUOpType.isAMOCASQ(uop.fuOpType) && stdCnt === StdCntCASQ.U || 17238c29594Szhanglinjuan LSUOpType.isAMOCASWD(uop.fuOpType) && stdCnt === StdCntCASWD.U || 17338c29594Szhanglinjuan !isAMOCAS && stdCnt === StdCntNCAS.U 17438c29594Szhanglinjuan ) 17538c29594Szhanglinjuan } 17638c29594Szhanglinjuan assert(stdCnt <= stds.length.U, "unexpected std") 17738c29594Szhanglinjuan assert(!(Cat(io.storeDataIn.map(_.fire)).orR && data_valid), "atomic unit re-receive data") 178024ee227SWilliam Wang 179204141efSGuanghui Cheng // atomic trigger 180204141efSGuanghui Cheng val csrCtrl = io.csrCtrl 181204141efSGuanghui Cheng val tdata = Reg(Vec(TriggerNum, new MatchTriggerIO)) 182204141efSGuanghui Cheng val tEnableVec = RegInit(VecInit(Seq.fill(TriggerNum)(false.B))) 183204141efSGuanghui Cheng tEnableVec := csrCtrl.mem_trigger.tEnableVec 184204141efSGuanghui Cheng when (csrCtrl.mem_trigger.tUpdate.valid) { 185204141efSGuanghui Cheng tdata(csrCtrl.mem_trigger.tUpdate.bits.addr) := csrCtrl.mem_trigger.tUpdate.bits.tdata 186204141efSGuanghui Cheng } 187204141efSGuanghui Cheng 188204141efSGuanghui Cheng val debugMode = csrCtrl.mem_trigger.debugMode 189204141efSGuanghui Cheng val triggerCanRaiseBpExp = csrCtrl.mem_trigger.triggerCanRaiseBpExp 190204141efSGuanghui Cheng val backendTriggerTimingVec = VecInit(tdata.map(_.timing)) 191204141efSGuanghui Cheng val backendTriggerChainVec = VecInit(tdata.map(_.chain)) 192204141efSGuanghui Cheng val backendTriggerHitVec = WireInit(VecInit(Seq.fill(TriggerNum)(false.B))) 193204141efSGuanghui Cheng val backendTriggerCanFireVec = RegInit(VecInit(Seq.fill(TriggerNum)(false.B))) 194204141efSGuanghui Cheng 19538c29594Szhanglinjuan assert(state === s_invalid || 19638c29594Szhanglinjuan uop.fuOpType(1,0) === "b10".U || 19738c29594Szhanglinjuan uop.fuOpType(1,0) === "b11".U || 19838c29594Szhanglinjuan LSUOpType.isAMOCASQ(uop.fuOpType), 19938c29594Szhanglinjuan "Only word or doubleword or quadword is supported" 20038c29594Szhanglinjuan ) 201204141efSGuanghui Cheng 202204141efSGuanghui Cheng // store trigger 203204141efSGuanghui Cheng val store_hit = Wire(Vec(TriggerNum, Bool())) 204204141efSGuanghui Cheng for (j <- 0 until TriggerNum) { 205204141efSGuanghui Cheng store_hit(j) := !tdata(j).select && !debugMode && isNotLr && TriggerCmp( 206204141efSGuanghui Cheng vaddr, 207204141efSGuanghui Cheng tdata(j).tdata2, 208204141efSGuanghui Cheng tdata(j).matchType, 209204141efSGuanghui Cheng tEnableVec(j) && tdata(j).store 210204141efSGuanghui Cheng ) 211204141efSGuanghui Cheng } 212204141efSGuanghui Cheng // load trigger 213204141efSGuanghui Cheng val load_hit = Wire(Vec(TriggerNum, Bool())) 214204141efSGuanghui Cheng for (j <- 0 until TriggerNum) { 215204141efSGuanghui Cheng load_hit(j) := !tdata(j).select && !debugMode && isNotSc && TriggerCmp( 216204141efSGuanghui Cheng vaddr, 217204141efSGuanghui Cheng tdata(j).tdata2, 218204141efSGuanghui Cheng tdata(j).matchType, 219204141efSGuanghui Cheng tEnableVec(j) && tdata(j).load 220204141efSGuanghui Cheng ) 221204141efSGuanghui Cheng } 222204141efSGuanghui Cheng backendTriggerHitVec := store_hit.zip(load_hit).map { case (sh, lh) => sh || lh } 223204141efSGuanghui Cheng // triggerCanFireVec will update at T+1 22438c29594Szhanglinjuan TriggerCheckCanFire(TriggerNum, backendTriggerCanFireVec, backendTriggerHitVec, 22538c29594Szhanglinjuan backendTriggerTimingVec, backendTriggerChainVec) 226204141efSGuanghui Cheng 227204141efSGuanghui Cheng val actionVec = VecInit(tdata.map(_.action)) 228204141efSGuanghui Cheng val triggerAction = Wire(TriggerAction()) 229204141efSGuanghui Cheng TriggerUtil.triggerActionGen(triggerAction, backendTriggerCanFireVec, actionVec, triggerCanRaiseBpExp) 230b0a60050SGuanghui Cheng val triggerDebugMode = TriggerAction.isDmode(triggerAction) 231b0a60050SGuanghui Cheng val triggerBreakpoint = TriggerAction.isExp(triggerAction) 232204141efSGuanghui Cheng 233024ee227SWilliam Wang // tlb translation, manipulating signals && deal with exception 23452180d7eShappy-lx // at the same time, flush sbuffer 23552180d7eShappy-lx when (state === s_tlb_and_flush_sbuffer_req) { 2366fce12d9SWilliam Wang // do not accept tlb resp in the first cycle 2376fce12d9SWilliam Wang // this limition is for hw prefetcher 2386fce12d9SWilliam Wang // when !have_sent_first_tlb_req, tlb resp may come from hw prefetch 2396fce12d9SWilliam Wang have_sent_first_tlb_req := true.B 2406fce12d9SWilliam Wang 2416fce12d9SWilliam Wang when (io.dtlb.resp.fire && have_sent_first_tlb_req) { 24203efd994Shappy-lx paddr := io.dtlb.resp.bits.paddr(0) 243d0de7e4aSpeixiaokun gpaddr := io.dtlb.resp.bits.gpaddr(0) 244189833a1SHaoyuan Feng vaddr := io.dtlb.resp.bits.fullva 245ad415ae0SXiaokun-Pei isForVSnonLeafPTE := io.dtlb.resp.bits.isForVSnonLeafPTE 246024ee227SWilliam Wang // exception handling 24738c29594Szhanglinjuan val addrAligned = LookupTree(uop.fuOpType(1,0), List( 24838c29594Szhanglinjuan "b10".U -> (vaddr(1,0) === 0.U), // W 24938c29594Szhanglinjuan "b11".U -> (vaddr(2,0) === 0.U), // D 25038c29594Szhanglinjuan "b00".U -> (vaddr(3,0) === 0.U) // Q 251024ee227SWilliam Wang )) 2528c343485SWilliam Wang exceptionVec(loadAddrMisaligned) := !addrAligned && isLr 2538c343485SWilliam Wang exceptionVec(storeAddrMisaligned) := !addrAligned && !isLr 25403efd994Shappy-lx exceptionVec(storePageFault) := io.dtlb.resp.bits.excp(0).pf.st 25503efd994Shappy-lx exceptionVec(loadPageFault) := io.dtlb.resp.bits.excp(0).pf.ld 25603efd994Shappy-lx exceptionVec(storeAccessFault) := io.dtlb.resp.bits.excp(0).af.st 25703efd994Shappy-lx exceptionVec(loadAccessFault) := io.dtlb.resp.bits.excp(0).af.ld 258d0de7e4aSpeixiaokun exceptionVec(storeGuestPageFault) := io.dtlb.resp.bits.excp(0).gpf.st 259d0de7e4aSpeixiaokun exceptionVec(loadGuestPageFault) := io.dtlb.resp.bits.excp(0).gpf.ld 260e9092fe2SLemover 261b0a60050SGuanghui Cheng exceptionVec(breakPoint) := triggerBreakpoint 262204141efSGuanghui Cheng trigger := triggerAction 263204141efSGuanghui Cheng 264e9092fe2SLemover when (!io.dtlb.resp.bits.miss) { 2658744445eSMaxpicca-Li io.out.bits.uop.debugInfo.tlbRespTime := GTimer() 266b0a60050SGuanghui Cheng when (!addrAligned || triggerDebugMode || triggerBreakpoint) { 267b0a60050SGuanghui Cheng // NOTE: when addrAligned or trigger fire, do not need to wait tlb actually 268e9092fe2SLemover // check for miss aligned exceptions, tlb exception are checked next cycle for timing 269024ee227SWilliam Wang // if there are exceptions, no need to execute it 270024ee227SWilliam Wang state := s_finish 2714f39c746SYinan Xu out_valid := true.B 272024ee227SWilliam Wang atom_override_xtval := true.B 273024ee227SWilliam Wang }.otherwise { 274ca2f90a6SLemover state := s_pm 275024ee227SWilliam Wang } 276024ee227SWilliam Wang } 277024ee227SWilliam Wang } 278e9092fe2SLemover } 279024ee227SWilliam Wang 280bb76fc1bSYanqin Li val pbmtReg = RegEnable(io.dtlb.resp.bits.pbmt(0), io.dtlb.resp.fire && !io.dtlb.resp.bits.miss) 281ca2f90a6SLemover when (state === s_pm) { 282cba0a7e0SLemover val pmp = WireInit(io.pmpResp) 283bb76fc1bSYanqin Li is_mmio := Pbmt.isIO(pbmtReg) || (Pbmt.isPMA(pbmtReg) && pmp.mmio) 284f9ac118cSHaoyuan Feng 285e9092fe2SLemover // NOTE: only handle load/store exception here, if other exception happens, don't send here 286e9092fe2SLemover val exception_va = exceptionVec(storePageFault) || exceptionVec(loadPageFault) || 287efe8c804Sxuzefan exceptionVec(storeGuestPageFault) || exceptionVec(loadGuestPageFault) || 288e9092fe2SLemover exceptionVec(storeAccessFault) || exceptionVec(loadAccessFault) 289*59ef52f3Szhanglinjuan val exception_pa_mmio_nc = pmp.mmio || Pbmt.isIO(pbmtReg) || Pbmt.isNC(pbmtReg) 290*59ef52f3Szhanglinjuan val exception_pa = pmp.st || pmp.ld || exception_pa_mmio_nc 291e9092fe2SLemover when (exception_va || exception_pa) { 292ca2f90a6SLemover state := s_finish 2934f39c746SYinan Xu out_valid := true.B 294ca2f90a6SLemover atom_override_xtval := true.B 295ca2f90a6SLemover }.otherwise { 29652180d7eShappy-lx // if sbuffer has been flushed, go to query dcache, otherwise wait for sbuffer. 29752180d7eShappy-lx state := Mux(sbuffer_empty, s_cache_req, s_wait_flush_sbuffer_resp); 298ca2f90a6SLemover } 2990fedb24cSWilliam Wang // update storeAccessFault bit 300*59ef52f3Szhanglinjuan exceptionVec(loadAccessFault) := exceptionVec(loadAccessFault) || 301*59ef52f3Szhanglinjuan (pmp.ld || exception_pa_mmio_nc) && isLr 302*59ef52f3Szhanglinjuan exceptionVec(storeAccessFault) := exceptionVec(storeAccessFault) || pmp.st || 303*59ef52f3Szhanglinjuan (pmp.ld || exception_pa_mmio_nc) && !isLr 304ca2f90a6SLemover } 305024ee227SWilliam Wang 30652180d7eShappy-lx when (state === s_wait_flush_sbuffer_resp) { 30752180d7eShappy-lx when (sbuffer_empty) { 308024ee227SWilliam Wang state := s_cache_req 309024ee227SWilliam Wang } 310024ee227SWilliam Wang } 311024ee227SWilliam Wang 31238c29594Szhanglinjuan def genWdataAMO(data: UInt, sizeEncode: UInt): UInt = { 31338c29594Szhanglinjuan LookupTree(sizeEncode(1, 0), List( 31438c29594Szhanglinjuan "b10".U -> Fill(4, data(31, 0)), 31538c29594Szhanglinjuan "b11".U -> Fill(2, data(63, 0)), 31638c29594Szhanglinjuan "b00".U -> data(127, 0) 317024ee227SWilliam Wang )) 31838c29594Szhanglinjuan } 319024ee227SWilliam Wang 32038c29594Szhanglinjuan def genWmaskAMO(addr: UInt, sizeEncode: UInt): UInt = { 32138c29594Szhanglinjuan /** 32238c29594Szhanglinjuan * `MainPipeReq` uses `word_idx` to recognize which 64-bits data bank to operate on. Double-word atomics are 32338c29594Szhanglinjuan * always 8B aligned and quad-word atomics are always 16B aligned except for misaligned exception, therefore 32438c29594Szhanglinjuan * `word_idx` is enough and there is no need to shift according address. Only word atomics needs LSBs of the 32538c29594Szhanglinjuan * address to shift mask inside a 64-bits aligned range. 32638c29594Szhanglinjuan */ 32738c29594Szhanglinjuan LookupTree(sizeEncode(1, 0), List( 32838c29594Szhanglinjuan "b10".U -> (0xf.U << addr(2,0)), // W 32938c29594Szhanglinjuan "b11".U -> 0xff.U, // D 33038c29594Szhanglinjuan "b00".U -> 0xffff.U // Q 33138c29594Szhanglinjuan )) 33238c29594Szhanglinjuan } 333024ee227SWilliam Wang 33438c29594Szhanglinjuan when (state === s_cache_req) { 3354f39c746SYinan Xu when (io.dcache.req.fire) { 336024ee227SWilliam Wang state := s_cache_resp 337024ee227SWilliam Wang } 338024ee227SWilliam Wang } 339024ee227SWilliam Wang 34062cb71fbShappy-lx val dcache_resp_data = Reg(UInt()) 34162cb71fbShappy-lx val dcache_resp_id = Reg(UInt()) 34262cb71fbShappy-lx val dcache_resp_error = Reg(Bool()) 34362cb71fbShappy-lx 344024ee227SWilliam Wang when (state === s_cache_resp) { 34562cb71fbShappy-lx // when not miss 34662cb71fbShappy-lx // everything is OK, simply send response back to sbuffer 34762cb71fbShappy-lx // when miss and not replay 34862cb71fbShappy-lx // wait for missQueue to handling miss and replaying our request 34962cb71fbShappy-lx // when miss and replay 35062cb71fbShappy-lx // req missed and fail to enter missQueue, manually replay it later 35162cb71fbShappy-lx // TODO: add assertions: 35262cb71fbShappy-lx // 1. add a replay delay counter? 35362cb71fbShappy-lx // 2. when req gets into MissQueue, it should not miss any more 354935edac4STang Haojin when (io.dcache.resp.fire) { 35562cb71fbShappy-lx when (io.dcache.resp.bits.miss) { 35662cb71fbShappy-lx when (io.dcache.resp.bits.replay) { 35762cb71fbShappy-lx state := s_cache_req 35862cb71fbShappy-lx } 35962cb71fbShappy-lx }.otherwise { 36062cb71fbShappy-lx dcache_resp_data := io.dcache.resp.bits.data 36162cb71fbShappy-lx dcache_resp_id := io.dcache.resp.bits.id 36262cb71fbShappy-lx dcache_resp_error := io.dcache.resp.bits.error 36362cb71fbShappy-lx state := s_cache_resp_latch 36462cb71fbShappy-lx } 36562cb71fbShappy-lx } 36662cb71fbShappy-lx } 36762cb71fbShappy-lx 36862cb71fbShappy-lx when (state === s_cache_resp_latch) { 36938c29594Szhanglinjuan success := dcache_resp_id 37038c29594Szhanglinjuan val rdataSel = Mux( 37138c29594Szhanglinjuan paddr(2, 0) === 0.U, 37238c29594Szhanglinjuan dcache_resp_data, 37338c29594Szhanglinjuan dcache_resp_data >> 32 37438c29594Szhanglinjuan ) 37538c29594Szhanglinjuan assert(paddr(2, 0) === "b000".U || paddr(2, 0) === "b100".U) 376024ee227SWilliam Wang 377074ad6aaSzhanglinjuan resp_data_wire := Mux( 378074ad6aaSzhanglinjuan isSc, 379074ad6aaSzhanglinjuan dcache_resp_data, 38038c29594Szhanglinjuan LookupTree(uop.fuOpType(1,0), List( 38138c29594Szhanglinjuan "b10".U -> SignExt(rdataSel(31, 0), QuadWordBits), // W 38238c29594Szhanglinjuan "b11".U -> SignExt(rdataSel(63, 0), QuadWordBits), // D 38338c29594Szhanglinjuan "b00".U -> rdataSel // Q 384024ee227SWilliam Wang )) 385074ad6aaSzhanglinjuan ) 386024ee227SWilliam Wang 38762cb71fbShappy-lx when (dcache_resp_error && io.csrCtrl.cache_error_enable) { 388026615fcSWilliam Wang exceptionVec(loadAccessFault) := isLr 389026615fcSWilliam Wang exceptionVec(storeAccessFault) := !isLr 390026615fcSWilliam Wang assert(!exceptionVec(loadAccessFault)) 391026615fcSWilliam Wang assert(!exceptionVec(storeAccessFault)) 392026615fcSWilliam Wang } 393026615fcSWilliam Wang 394f97664b3Swangkaifan resp_data := resp_data_wire 395024ee227SWilliam Wang state := s_finish 3964f39c746SYinan Xu out_valid := true.B 397024ee227SWilliam Wang } 398024ee227SWilliam Wang 39938c29594Szhanglinjuan when (state === s_finish) { 4004f39c746SYinan Xu when (io.out.fire) { 40138c29594Szhanglinjuan when (LSUOpType.isAMOCASQ(uop.fuOpType)) { 40238c29594Szhanglinjuan // enter `s_finish2` to write the 2nd uop back 40338c29594Szhanglinjuan state := s_finish2 40438c29594Szhanglinjuan out_valid := true.B 40538c29594Szhanglinjuan }.otherwise { 40638c29594Szhanglinjuan // otherwise the FSM ends here 40738c29594Szhanglinjuan resetFSM() 40838c29594Szhanglinjuan } 40938c29594Szhanglinjuan } 410024ee227SWilliam Wang } 4114f39c746SYinan Xu 41238c29594Szhanglinjuan when (state === s_finish2) { 41338c29594Szhanglinjuan when (io.out.fire) { 41438c29594Szhanglinjuan resetFSM() 41538c29594Szhanglinjuan } 416024ee227SWilliam Wang } 417024ee227SWilliam Wang 418f4b2089aSYinan Xu when (io.redirect.valid) { 419024ee227SWilliam Wang atom_override_xtval := false.B 420024ee227SWilliam Wang } 4218a5bdd64Swangkaifan 42238c29594Szhanglinjuan def resetFSM(): Unit = { 42338c29594Szhanglinjuan state := s_invalid 42438c29594Szhanglinjuan out_valid := false.B 42538c29594Szhanglinjuan data_valid := false.B 42638c29594Szhanglinjuan stdCnt := 0.U 42738c29594Szhanglinjuan pdest1Valid := false.B 42838c29594Szhanglinjuan pdest2Valid := false.B 42938c29594Szhanglinjuan } 43038c29594Szhanglinjuan 43138c29594Szhanglinjuan /** 43238c29594Szhanglinjuan * IO assignment 43338c29594Szhanglinjuan */ 43438c29594Szhanglinjuan io.exceptionInfo.valid := atom_override_xtval 43538c29594Szhanglinjuan io.exceptionInfo.bits.vaddr := vaddr 43638c29594Szhanglinjuan io.exceptionInfo.bits.gpaddr := gpaddr 43738c29594Szhanglinjuan io.exceptionInfo.bits.isForVSnonLeafPTE := isForVSnonLeafPTE 43838c29594Szhanglinjuan 43938c29594Szhanglinjuan // Send TLB feedback to store issue queue 44038c29594Szhanglinjuan // we send feedback right after we receives request 44138c29594Szhanglinjuan // also, we always treat amo as tlb hit 44238c29594Szhanglinjuan // since we will continue polling tlb all by ourself 44338c29594Szhanglinjuan io.feedbackSlow.valid := GatedValidRegNext(GatedValidRegNext(io.in.valid)) 44438c29594Szhanglinjuan io.feedbackSlow.bits.hit := true.B 44538c29594Szhanglinjuan io.feedbackSlow.bits.robIdx := RegEnable(io.in.bits.uop.robIdx, io.in.valid) 44638c29594Szhanglinjuan io.feedbackSlow.bits.sqIdx := RegEnable(io.in.bits.uop.sqIdx, io.in.valid) 44738c29594Szhanglinjuan io.feedbackSlow.bits.lqIdx := RegEnable(io.in.bits.uop.lqIdx, io.in.valid) 44838c29594Szhanglinjuan io.feedbackSlow.bits.flushState := DontCare 44938c29594Szhanglinjuan io.feedbackSlow.bits.sourceType := DontCare 45038c29594Szhanglinjuan io.feedbackSlow.bits.dataInvalidSqIdx := DontCare 45138c29594Szhanglinjuan 45238c29594Szhanglinjuan // send req to dtlb 45338c29594Szhanglinjuan // keep firing until tlb hit 45438c29594Szhanglinjuan io.dtlb.req.valid := state === s_tlb_and_flush_sbuffer_req 45538c29594Szhanglinjuan io.dtlb.req.bits.vaddr := vaddr 45638c29594Szhanglinjuan io.dtlb.req.bits.fullva := vaddr 45738c29594Szhanglinjuan io.dtlb.req.bits.checkfullva := true.B 45838c29594Szhanglinjuan io.dtlb.resp.ready := true.B 45938c29594Szhanglinjuan io.dtlb.req.bits.cmd := Mux(isLr, TlbCmd.atom_read, TlbCmd.atom_write) 46038c29594Szhanglinjuan io.dtlb.req.bits.debug.pc := uop.pc 46138c29594Szhanglinjuan io.dtlb.req.bits.debug.robIdx := uop.robIdx 46238c29594Szhanglinjuan io.dtlb.req.bits.debug.isFirstIssue := false.B 46338c29594Szhanglinjuan io.out.bits.uop.debugInfo.tlbFirstReqTime := GTimer() // FIXME lyq: it will be always assigned 46438c29594Szhanglinjuan 46538c29594Szhanglinjuan // send req to sbuffer to flush it if it is not empty 46638c29594Szhanglinjuan io.flush_sbuffer.valid := !sbuffer_empty && state === s_tlb_and_flush_sbuffer_req 46738c29594Szhanglinjuan 46838c29594Szhanglinjuan // When is sta issue port ready: 46938c29594Szhanglinjuan // (1) AtomicsUnit is idle, or 47038c29594Szhanglinjuan // (2) For AMOCAS.Q, the second uop with the pdest of the higher bits of rd is not received yet 47138c29594Szhanglinjuan io.in.ready := state === s_invalid || LSUOpType.isAMOCASQ(uop.fuOpType) && (!pdest2Valid || !pdest1Valid) 47238c29594Szhanglinjuan 47338c29594Szhanglinjuan io.out.valid := out_valid && Mux(state === s_finish2, pdest2Valid, pdest1Valid) 47438c29594Szhanglinjuan XSError((state === s_finish || state === s_finish2) =/= out_valid, "out_valid reg error\n") 47538c29594Szhanglinjuan io.out.bits := DontCare 47638c29594Szhanglinjuan io.out.bits.uop := uop 47738c29594Szhanglinjuan io.out.bits.uop.fuType := FuType.mou.U 47838c29594Szhanglinjuan io.out.bits.uop.pdest := Mux(state === s_finish2, pdest2, pdest1) 47938c29594Szhanglinjuan io.out.bits.uop.exceptionVec := exceptionVec 48038c29594Szhanglinjuan io.out.bits.uop.trigger := trigger 48138c29594Szhanglinjuan io.out.bits.data := Mux(state === s_finish2, resp_data >> XLEN, resp_data) 48238c29594Szhanglinjuan io.out.bits.debug.isMMIO := is_mmio 48338c29594Szhanglinjuan io.out.bits.debug.paddr := paddr 48438c29594Szhanglinjuan 48538c29594Szhanglinjuan io.dcache.req.valid := Mux( 48638c29594Szhanglinjuan io.dcache.req.bits.cmd === M_XLR, 48738c29594Szhanglinjuan !io.dcache.block_lr, // block lr to survive in lr storm 48838c29594Szhanglinjuan data_valid // wait until src(1) is ready 48938c29594Szhanglinjuan ) && state === s_cache_req 49038c29594Szhanglinjuan val pipe_req = io.dcache.req.bits 49138c29594Szhanglinjuan pipe_req := DontCare 49238c29594Szhanglinjuan pipe_req.cmd := LookupTree(uop.fuOpType, List( 49338c29594Szhanglinjuan // TODO: optimize this 49438c29594Szhanglinjuan LSUOpType.lr_w -> M_XLR, 49538c29594Szhanglinjuan LSUOpType.sc_w -> M_XSC, 49638c29594Szhanglinjuan LSUOpType.amoswap_w -> M_XA_SWAP, 49738c29594Szhanglinjuan LSUOpType.amoadd_w -> M_XA_ADD, 49838c29594Szhanglinjuan LSUOpType.amoxor_w -> M_XA_XOR, 49938c29594Szhanglinjuan LSUOpType.amoand_w -> M_XA_AND, 50038c29594Szhanglinjuan LSUOpType.amoor_w -> M_XA_OR, 50138c29594Szhanglinjuan LSUOpType.amomin_w -> M_XA_MIN, 50238c29594Szhanglinjuan LSUOpType.amomax_w -> M_XA_MAX, 50338c29594Szhanglinjuan LSUOpType.amominu_w -> M_XA_MINU, 50438c29594Szhanglinjuan LSUOpType.amomaxu_w -> M_XA_MAXU, 50538c29594Szhanglinjuan LSUOpType.amocas_w -> M_XA_CASW, 50638c29594Szhanglinjuan 50738c29594Szhanglinjuan LSUOpType.lr_d -> M_XLR, 50838c29594Szhanglinjuan LSUOpType.sc_d -> M_XSC, 50938c29594Szhanglinjuan LSUOpType.amoswap_d -> M_XA_SWAP, 51038c29594Szhanglinjuan LSUOpType.amoadd_d -> M_XA_ADD, 51138c29594Szhanglinjuan LSUOpType.amoxor_d -> M_XA_XOR, 51238c29594Szhanglinjuan LSUOpType.amoand_d -> M_XA_AND, 51338c29594Szhanglinjuan LSUOpType.amoor_d -> M_XA_OR, 51438c29594Szhanglinjuan LSUOpType.amomin_d -> M_XA_MIN, 51538c29594Szhanglinjuan LSUOpType.amomax_d -> M_XA_MAX, 51638c29594Szhanglinjuan LSUOpType.amominu_d -> M_XA_MINU, 51738c29594Szhanglinjuan LSUOpType.amomaxu_d -> M_XA_MAXU, 51838c29594Szhanglinjuan LSUOpType.amocas_d -> M_XA_CASD, 51938c29594Szhanglinjuan 52038c29594Szhanglinjuan LSUOpType.amocas_q -> M_XA_CASQ 52138c29594Szhanglinjuan )) 52238c29594Szhanglinjuan pipe_req.miss := false.B 52338c29594Szhanglinjuan pipe_req.probe := false.B 52438c29594Szhanglinjuan pipe_req.probe_need_data := false.B 52538c29594Szhanglinjuan pipe_req.source := AMO_SOURCE.U 52638c29594Szhanglinjuan pipe_req.addr := get_block_addr(paddr) 52738c29594Szhanglinjuan pipe_req.vaddr := get_block_addr(vaddr) 52838c29594Szhanglinjuan pipe_req.word_idx := get_word(paddr) 52938c29594Szhanglinjuan pipe_req.amo_data := genWdataAMO(rs2, uop.fuOpType) 53038c29594Szhanglinjuan pipe_req.amo_mask := genWmaskAMO(paddr, uop.fuOpType) 53138c29594Szhanglinjuan pipe_req.amo_cmp := genWdataAMO(rd, uop.fuOpType) 53238c29594Szhanglinjuan 5331545277aSYinan Xu if (env.EnableDifftest) { 5347d45a146SYinan Xu val difftest = DifftestModule(new DiffAtomicEvent) 53538c29594Szhanglinjuan val en = io.dcache.req.fire 5367d45a146SYinan Xu difftest.coreid := io.hartId 5377d45a146SYinan Xu difftest.valid := state === s_cache_resp_latch 53838c29594Szhanglinjuan difftest.addr := RegEnable(paddr, en) 53938c29594Szhanglinjuan difftest.data := RegEnable(io.dcache.req.bits.amo_data.asTypeOf(difftest.data), en) 54038c29594Szhanglinjuan difftest.mask := RegEnable(io.dcache.req.bits.amo_mask, en) 54138c29594Szhanglinjuan difftest.cmp := RegEnable(io.dcache.req.bits.amo_cmp.asTypeOf(difftest.cmp), en) 54238c29594Szhanglinjuan difftest.fuop := RegEnable(uop.fuOpType, en) 54338c29594Szhanglinjuan difftest.out := resp_data_wire.asTypeOf(difftest.out) 5448a5bdd64Swangkaifan } 545e13d224aSYinan Xu 546e13d224aSYinan Xu if (env.EnableDifftest || env.AlwaysBasicDiff) { 547e13d224aSYinan Xu val uop = io.out.bits.uop 5487d45a146SYinan Xu val difftest = DifftestModule(new DiffLrScEvent) 5497d45a146SYinan Xu difftest.coreid := io.hartId 55038c29594Szhanglinjuan difftest.valid := io.out.fire && state === s_finish && isSc 55138c29594Szhanglinjuan difftest.success := success 552e13d224aSYinan Xu } 553024ee227SWilliam Wang} 554