xref: /XiangShan/src/main/scala/xiangshan/mem/pipeline/AtomicsUnit.scala (revision 1592abd11eecf7bec0f1453ffe4a7617167f8ba9)
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