xref: /XiangShan/src/main/scala/xiangshan/backend/fu/NewCSR/CSREvents/TrapEntryHSEvent.scala (revision 21e8685b69102452bb454870742496551ca56ad2)
1package xiangshan.backend.fu.NewCSR.CSREvents
2
3import chisel3._
4import chisel3.util._
5import org.chipsalliance.cde.config.Parameters
6import utility.{SignExt, ZeroExt}
7import xiangshan.ExceptionNO
8import xiangshan.backend.fu.NewCSR.CSRBundles.{CauseBundle, OneFieldBundle, PrivState}
9import xiangshan.backend.fu.NewCSR.CSRConfig.{VaddrMaxWidth, XLEN}
10import xiangshan.backend.fu.NewCSR.CSRDefines.SatpMode
11import xiangshan.backend.fu.NewCSR._
12import xiangshan.AddrTransType
13
14
15class TrapEntryHSEventOutput extends Bundle with EventUpdatePrivStateOutput with EventOutputBase  {
16
17  // Todo: use sstatus instead of mstatus
18  val mstatus = ValidIO((new MstatusBundle ).addInEvent(_.SPP, _.SPIE, _.SIE, _.SDT))
19  val hstatus = ValidIO((new HstatusBundle ).addInEvent(_.SPV, _.SPVP, _.GVA))
20  val sepc    = ValidIO((new Epc           ).addInEvent(_.epc))
21  val scause  = ValidIO((new CauseBundle   ).addInEvent(_.Interrupt, _.ExceptionCode))
22  val stval   = ValidIO((new OneFieldBundle).addInEvent(_.ALL))
23  val htval   = ValidIO((new OneFieldBundle).addInEvent(_.ALL))
24  val htinst  = ValidIO((new OneFieldBundle).addInEvent(_.ALL))
25  val targetPc  = ValidIO(new TargetPCBundle)
26}
27
28class TrapEntryHSEventModule(implicit val p: Parameters) extends Module with CSREventBase {
29  val in = IO(new TrapEntryEventInput)
30  val out = IO(new TrapEntryHSEventOutput)
31
32  private val current = in
33  private val iMode = current.iMode
34  private val dMode = current.dMode
35  private val satp = current.satp
36  private val vsatp = current.vsatp
37  private val hgatp = current.hgatp
38
39  private val highPrioTrapNO = in.causeNO.ExceptionCode.asUInt
40  private val isException = !in.causeNO.Interrupt.asBool
41  private val isInterrupt = in.causeNO.Interrupt.asBool
42
43  private val trapPC = genTrapVA(
44    iMode,
45    satp,
46    vsatp,
47    hgatp,
48    in.trapPc,
49  )
50
51  private val trapPCGPA = in.trapPcGPA
52
53  private val trapMemVA = in.memExceptionVAddr
54
55  private val trapMemGPA = in.memExceptionGPAddr
56
57  private val trapInst = Mux(in.trapInst.valid, in.trapInst.bits, 0.U)
58
59  private val fetchIsVirt = current.iMode.isVirtual
60  private val memIsVirt   = current.dMode.isVirtual
61
62  private val isFetchExcp    = isException && ExceptionNO.getFetchFault.map(_.U === highPrioTrapNO).reduce(_ || _)
63  private val isMemExcp      = isException && (ExceptionNO.getLoadFault ++ ExceptionNO.getStoreFault).map(_.U === highPrioTrapNO).reduce(_ || _)
64  private val isBpExcp       = isException && ExceptionNO.EX_BP.U === highPrioTrapNO
65  private val isFetchBkpt    = isBpExcp && in.isFetchBkpt
66  private val isMemBkpt      = isBpExcp && !in.isFetchBkpt
67  private val isHlsExcp      = isException && in.isHls
68  private val fetchCrossPage = in.isCrossPageIPF
69  private val isFetchMalAddr = in.isFetchMalAddr
70  private val isFetchMalAddrExcp = isException && isFetchMalAddr
71  private val isIllegalInst  = isException && (ExceptionNO.EX_II.U === highPrioTrapNO || ExceptionNO.EX_VI.U === highPrioTrapNO)
72
73  private val isLSGuestExcp    = isException && ExceptionNO.getLSGuestPageFault.map(_.U === highPrioTrapNO).reduce(_ || _)
74  private val isFetchGuestExcp = isException && ExceptionNO.EX_IGPF.U === highPrioTrapNO
75  // Software breakpoint exceptions are permitted to write either 0 or the pc to xtval
76  // We fill pc here
77  private val tvalFillPc       = (isFetchExcp || isFetchGuestExcp) && !fetchCrossPage || isFetchBkpt
78  private val tvalFillPcPlus2  = (isFetchExcp || isFetchGuestExcp) && fetchCrossPage
79  private val tvalFillMemVaddr = isMemExcp || isMemBkpt
80  private val tvalFillGVA      =
81    isHlsExcp && isMemExcp ||
82    isLSGuestExcp|| isFetchGuestExcp ||
83    (isFetchExcp || isFetchBkpt) && fetchIsVirt ||
84    (isMemExcp || isMemBkpt) && memIsVirt
85  private val tvalFillInst     = isIllegalInst
86
87  private val tval = Mux1H(Seq(
88    (tvalFillPc                        ) -> trapPC,
89    (tvalFillPcPlus2                   ) -> (trapPC + 2.U),
90    (tvalFillMemVaddr || isLSGuestExcp ) -> trapMemVA,
91    (tvalFillInst                      ) -> trapInst,
92  ))
93
94  private val tval2 = Mux1H(Seq(
95    (isFetchGuestExcp && isFetchMalAddr                    ) -> in.fetchMalTval,
96    (isFetchGuestExcp && !isFetchMalAddr && !fetchCrossPage) -> trapPCGPA,
97    (isFetchGuestExcp && !isFetchMalAddr && fetchCrossPage ) -> (trapPCGPA + 2.U),
98    (isLSGuestExcp                                         ) -> trapMemGPA,
99  ))
100
101  private val instrAddrTransType = AddrTransType(
102    bare = satp.MODE === SatpMode.Bare,
103    sv39 = satp.MODE === SatpMode.Sv39,
104    sv48 = satp.MODE === SatpMode.Sv48,
105    sv39x4 = false.B,
106    sv48x4 = false.B
107  )
108
109  out := DontCare
110
111  out.privState.valid := valid
112  out.mstatus  .valid := valid
113  out.hstatus  .valid := valid
114  out.sepc     .valid := valid
115  out.scause   .valid := valid
116  out.stval    .valid := valid
117  out.htval    .valid := valid
118  out.htinst   .valid := valid
119  out.targetPc .valid := valid
120
121  out.privState.bits            := PrivState.ModeHS
122  // mstatus
123  out.mstatus.bits.SPP          := current.privState.PRVM.asUInt(0, 0) // SPP is not PrivMode enum type, so asUInt and shrink the width
124  out.mstatus.bits.SPIE         := current.sstatus.SIE
125  out.mstatus.bits.SIE          := 0.U
126  out.mstatus.bits.SDT          := in.menvcfg.DTE.asBool // when DTE open set SDT to 1, else SDT is readonly 0
127  // hstatus
128  out.hstatus.bits.SPV          := current.privState.V
129    // SPVP is not PrivMode enum type, so asUInt and shrink the width
130  out.hstatus.bits.SPVP         := Mux(!current.privState.isVirtual, in.hstatus.SPVP.asUInt, current.privState.PRVM.asUInt(0, 0))
131  out.hstatus.bits.GVA          := tvalFillGVA
132  out.sepc.bits.epc             := Mux(isFetchMalAddr, in.fetchMalTval(63, 1), trapPC(63, 1))
133  out.scause.bits.Interrupt     := isInterrupt
134  out.scause.bits.ExceptionCode := highPrioTrapNO
135  out.stval.bits.ALL            := Mux(isFetchMalAddrExcp, in.fetchMalTval, tval)
136  out.htval.bits.ALL            := tval2 >> 2
137  out.htinst.bits.ALL           := Mux(isFetchGuestExcp && in.trapIsForVSnonLeafPTE || isLSGuestExcp && in.memExceptionIsForVSnonLeafPTE, 0x3000.U, 0.U)
138  out.targetPc.bits.pc          := in.pcFromXtvec
139  out.targetPc.bits.raiseIPF    := instrAddrTransType.checkPageFault(in.pcFromXtvec)
140  out.targetPc.bits.raiseIAF    := instrAddrTransType.checkAccessFault(in.pcFromXtvec)
141  out.targetPc.bits.raiseIGPF   := false.B
142
143  dontTouch(isLSGuestExcp)
144  dontTouch(tvalFillGVA)
145}
146
147trait TrapEntryHSEventSinkBundle extends EventSinkBundle { self: CSRModule[_ <: CSRBundle] =>
148  val trapToHS = IO(Flipped(new TrapEntryHSEventOutput))
149
150  addUpdateBundleInCSREnumType(trapToHS.getBundleByName(self.modName.toLowerCase()))
151
152  reconnectReg()
153}
154