xref: /XiangShan/src/main/scala/xiangshan/backend/fu/NewCSR/CSREvents/TrapEntryVSEvent.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.{HgatpMode, SatpMode}
11import xiangshan.backend.fu.NewCSR._
12import xiangshan.AddrTransType
13
14
15class TrapEntryVSEventOutput extends Bundle with EventUpdatePrivStateOutput with EventOutputBase  {
16
17  val vsstatus = ValidIO((new SstatusBundle ).addInEvent(_.SPP, _.SPIE, _.SIE, _.SDT))
18  val vsepc    = ValidIO((new Epc           ).addInEvent(_.epc))
19  val vscause  = ValidIO((new CauseBundle   ).addInEvent(_.Interrupt, _.ExceptionCode))
20  val vstval   = ValidIO((new OneFieldBundle).addInEvent(_.ALL))
21  val targetPc = ValidIO(new TargetPCBundle)
22}
23
24class TrapEntryVSEventModule(implicit val p: Parameters) extends Module with CSREventBase {
25  val in = IO(new TrapEntryEventInput)
26  val out = IO(new TrapEntryVSEventOutput)
27
28  when (valid) {
29    assert(in.privState.isVirtual, "The mode must be VU or VS when entry VS mode")
30  }
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 trapCode = in.causeNO.ExceptionCode.asUInt
40  private val isException = !in.causeNO.Interrupt.asBool
41  private val isInterrupt = in.causeNO.Interrupt.asBool
42  private val virtualInterruptIsHvictlInject = in.virtualInterruptIsHvictlInject
43  private val hvictlIID = in.hvictlIID
44
45  when(valid && isInterrupt && !virtualInterruptIsHvictlInject) {
46    assert(
47      (InterruptNO.getVS ++ InterruptNO.getLocal).map(_.U === trapCode).reduce(_ || _),
48      "The VS mode can only handle VSEI, VSTI, VSSI and local interrupts"
49    )
50  }
51
52  private val highPrioTrapNO = Mux(
53    InterruptNO.getVS.map(_.U === trapCode).reduce(_ || _) && isInterrupt,
54    trapCode - 1.U, // map VSSIP, VSTIP, VSEIP to SSIP, STIP, SEIP
55    trapCode,
56  )
57
58  private val trapPC = genTrapVA(
59    iMode,
60    satp,
61    vsatp,
62    hgatp,
63    in.trapPc,
64  )
65
66  private val trapMemVA = in.memExceptionVAddr
67
68  private val trapMemGPA = in.memExceptionGPAddr
69
70  private val trapInst = Mux(in.trapInst.valid, in.trapInst.bits, 0.U)
71
72  private val fetchIsVirt = current.iMode.isVirtual
73  private val memIsVirt   = current.dMode.isVirtual
74
75  private val isFetchExcp    = isException && Seq(/*EX_IAM, */ EX_IAF, EX_IPF).map(_.U === highPrioTrapNO).reduce(_ || _)
76  private val isMemExcp      = isException && Seq(EX_LAM, EX_LAF, EX_SAM, EX_SAF, EX_LPF, EX_SPF).map(_.U === highPrioTrapNO).reduce(_ || _)
77  private val isBpExcp       = isException && EX_BP.U === highPrioTrapNO
78  private val isFetchBkpt    = isBpExcp && in.isFetchBkpt
79  private val isMemBkpt      = isBpExcp && !in.isFetchBkpt
80  private val fetchCrossPage = in.isCrossPageIPF
81  private val isFetchMalAddr = in.isFetchMalAddr
82  private val isFetchMalAddrExcp = isException && isFetchMalAddr
83  private val isIllegalInst  = isException && (EX_II.U === highPrioTrapNO || EX_VI.U === highPrioTrapNO)
84
85  // Software breakpoint exceptions are permitted to write either 0 or the pc to xtval
86  // We fill pc here
87  private val tvalFillPc       = isFetchExcp && !fetchCrossPage || isFetchBkpt
88  private val tvalFillPcPlus2  = isFetchExcp && fetchCrossPage
89  private val tvalFillMemVaddr = isMemExcp || isMemBkpt
90  private val tvalFillGVA      =
91    (isFetchExcp || isFetchBkpt) && fetchIsVirt ||
92    (isMemExcp || isMemBkpt) && memIsVirt
93  private val tvalFillInst     = isIllegalInst
94
95  private val tval = Mux1H(Seq(
96    tvalFillPc       -> trapPC,
97    tvalFillPcPlus2  -> (trapPC + 2.U),
98    tvalFillMemVaddr -> trapMemVA,
99    tvalFillInst     -> trapInst,
100  ))
101
102  private val instrAddrTransType = AddrTransType(
103    bare = vsatp.MODE === SatpMode.Bare && hgatp.MODE === HgatpMode.Bare,
104    sv39 = vsatp.MODE === SatpMode.Sv39,
105    sv48 = vsatp.MODE === SatpMode.Sv48,
106    sv39x4 = vsatp.MODE === SatpMode.Bare && hgatp.MODE === HgatpMode.Sv39x4,
107    sv48x4 = vsatp.MODE === SatpMode.Bare && hgatp.MODE === HgatpMode.Sv48x4
108  )
109
110  out := DontCare
111
112  out.privState.valid := valid
113
114  out.vsstatus .valid := valid
115  out.vsepc    .valid := valid
116  out.vscause  .valid := valid
117  out.vstval   .valid := valid
118  out.targetPc .valid := valid
119
120  out.privState.bits             := PrivState.ModeVS
121  // vsstatus
122  out.vsstatus.bits.SPP          := current.privState.PRVM.asUInt(0, 0) // SPP is not PrivMode enum type, so asUInt and shrink the width
123  out.vsstatus.bits.SPIE         := current.vsstatus.SIE
124  out.vsstatus.bits.SIE          := 0.U
125  out.vsstatus.bits.SDT          := in.henvcfg.DTE.asBool // when DTE open set SDT to 1, else SDT is readonly 0
126  // SPVP is not PrivMode enum type, so asUInt and shrink the width
127  out.vsepc.bits.epc             := Mux(isFetchMalAddr, in.fetchMalTval(63, 1), trapPC(63, 1))
128  out.vscause.bits.Interrupt     := isInterrupt
129  out.vscause.bits.ExceptionCode := Mux(virtualInterruptIsHvictlInject, hvictlIID, highPrioTrapNO)
130  out.vstval.bits.ALL            := Mux(isFetchMalAddrExcp, in.fetchMalTval, tval)
131  out.targetPc.bits.pc           := in.pcFromXtvec
132  out.targetPc.bits.raiseIPF     := instrAddrTransType.checkPageFault(in.pcFromXtvec)
133  out.targetPc.bits.raiseIAF     := instrAddrTransType.checkAccessFault(in.pcFromXtvec)
134  out.targetPc.bits.raiseIGPF    := instrAddrTransType.checkGuestPageFault(in.pcFromXtvec)
135
136  dontTouch(tvalFillGVA)
137}
138
139trait TrapEntryVSEventSinkBundle extends EventSinkBundle { self: CSRModule[_ <: CSRBundle] =>
140  val trapToVS = IO(Flipped(new TrapEntryVSEventOutput))
141
142  addUpdateBundleInCSREnumType(trapToVS.getBundleByName(self.modName.toLowerCase()))
143
144  reconnectReg()
145}
146