xref: /XiangShan/src/main/scala/xiangshan/backend/fu/Fence.scala (revision d0b8aa5bb2c8f4c09acb9ae82a1a94b2252d802e)
1package xiangshan.backend.exu
2
3import chisel3._
4import chisel3.util._
5import xiangshan._
6import utils._
7import chisel3.util.experimental.BoringUtils
8
9import xiangshan.backend.FenceOpType
10
11class FenceExeUnit extends Exu(Exu.fenceExeUnitCfg) {
12  val (valid, src1, src2, uop, func, lsrc1, lsrc2) =
13    (io.in.valid, io.in.bits.src1, io.in.bits.src2, io.in.bits.uop, io.in.bits.uop.ctrl.fuOpType, io.in.bits.uop.ctrl.lsrc1, io.in.bits.uop.ctrl.lsrc2)
14
15  val s_sb :: s_tlb :: s_icache :: Nil = Enum(3)
16  val state = RegInit(s_sb)
17
18  val sfence  = WireInit(0.U.asTypeOf(new SfenceBundle))
19  val sbuffer = WireInit(false.B)
20  val fencei  = WireInit(false.B)
21  val sbEmpty = WireInit(false.B)
22  BoringUtils.addSource(sbuffer, "FenceUnitSbufferFlush")
23  BoringUtils.addSource(sfence, "SfenceBundle")
24  BoringUtils.addSource(fencei,  "FenceI")
25  BoringUtils.addSink(sbEmpty, "SBufferEmpty")
26  // NOTE: icache & tlb & sbuffer must receive flush signal at any time
27  sbuffer      := valid && state === s_sb && !sbEmpty
28  fencei       := (state === s_icache && sbEmpty) || (state === s_sb && valid && sbEmpty && func === FenceOpType.fencei)
29  sfence.valid := (state === s_tlb && sbEmpty) || (state === s_sb && valid && sbEmpty && func === FenceOpType.sfence)
30  sfence.bits.rs1  := Mux(state === s_sb, lsrc1 === 0.U, RegEnable(lsrc1 === 0.U, io.in.fire()))
31  sfence.bits.rs2  := Mux(state === s_sb, lsrc2 === 0.U, RegEnable(lsrc2 === 0.U, io.in.fire()))
32  sfence.bits.addr := Mux(state === s_sb, src1,          RegEnable(src1, io.in.fire()))
33
34  when (state === s_sb && valid && func === FenceOpType.fencei && !sbEmpty) { state := s_icache }
35  when (state === s_sb && valid && func === FenceOpType.sfence && !sbEmpty) { state := s_tlb }
36  when (state =/= s_sb && sbEmpty) { state := s_sb }
37
38  assert(!(io.out.valid && io.out.bits.uop.ctrl.rfWen))
39  io.in.ready := state === s_sb
40  io.out.valid := (state =/= s_sb && sbEmpty) || (state === s_sb && sbEmpty && valid)
41  io.out.bits.data := DontCare
42  io.out.bits.uop := Mux(state === s_sb, uop, RegEnable(uop, io.in.fire()))
43  io.out.bits.redirect <> DontCare
44  io.out.bits.redirectValid := false.B
45  io.out.bits.debug <> DontCare
46
47  assert(!(valid || state =/= s_sb) || io.out.ready) // NOTE: fence instr must be the first(only one) instr, so io.out.ready must be true
48
49  XSDebug(valid || state=/=s_sb || io.out.valid, p"In(${io.in.valid} ${io.in.ready}) Out(${io.out.valid} ${io.out.ready}) state:${state} sbuffer(flush:${sbuffer} empty:${sbEmpty}) fencei:${fencei} sfence:${sfence} Inpc:0x${Hexadecimal(io.in.bits.uop.cf.pc)} InroqIdx:${io.in.bits.uop.roqIdx} Outpc:0x${Hexadecimal(io.out.bits.uop.cf.pc)} OutroqIdx:${io.out.bits.uop.roqIdx}\n")
50}