xref: /XiangShan/src/main/scala/xiangshan/backend/fu/NewCSR/CSREvents/TrapEntryHSEvent.scala (revision 887862dbb8debde8ab099befc426493834a69ee7)
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._
12
13
14class TrapEntryHSEventOutput extends Bundle with EventUpdatePrivStateOutput with EventOutputBase  {
15
16  // Todo: use sstatus instead of mstatus
17  val mstatus = ValidIO((new MstatusBundle ).addInEvent(_.SPP, _.SPIE, _.SIE))
18  val hstatus = ValidIO((new HstatusBundle ).addInEvent(_.SPV, _.SPVP, _.GVA))
19  val sepc    = ValidIO((new Epc           ).addInEvent(_.epc))
20  val scause  = ValidIO((new CauseBundle   ).addInEvent(_.Interrupt, _.ExceptionCode))
21  val stval   = ValidIO((new OneFieldBundle).addInEvent(_.ALL))
22  val htval   = ValidIO((new OneFieldBundle).addInEvent(_.ALL))
23  val htinst  = ValidIO((new OneFieldBundle).addInEvent(_.ALL))
24  val targetPc = ValidIO(UInt(VaddrMaxWidth.W))
25
26  def getBundleByName(name: String): Valid[CSRBundle] = {
27    name match {
28      case "mstatus" => this.mstatus
29      case "hstatus" => this.hstatus
30      case "sepc"    => this.sepc
31      case "scause"  => this.scause
32      case "stval"   => this.stval
33      case "htval"   => this.htval
34      case "htinst"  => this.htinst
35    }
36  }
37}
38
39class TrapEntryHSEventModule(implicit val p: Parameters) extends Module with CSREventBase {
40  val in = IO(new TrapEntryEventInput)
41  val out = IO(new TrapEntryHSEventOutput)
42
43  private val current = in
44  private val iMode = current.iMode
45  private val dMode = current.dMode
46  private val satp = current.satp
47  private val vsatp = current.vsatp
48  private val hgatp = current.hgatp
49
50  private val highPrioTrapNO = in.causeNO.ExceptionCode.asUInt
51  private val isException = !in.causeNO.Interrupt.asBool
52  private val isInterrupt = in.causeNO.Interrupt.asBool
53
54  private val trapPC = genTrapVA(
55    iMode,
56    satp,
57    vsatp,
58    hgatp,
59    in.trapPc,
60  )
61
62  private val trapPCGPA = SignExt(in.trapPcGPA, XLEN)
63
64  private val trapMemVA = genTrapVA(
65    dMode,
66    satp,
67    vsatp,
68    hgatp,
69    in.memExceptionVAddr,
70  )
71
72  private val trapMemGPA = SignExt(in.memExceptionGPAddr, XLEN)
73
74  private val trapInst = Mux(in.trapInst.valid, in.trapInst.bits, 0.U)
75
76  private val fetchIsVirt = current.iMode.isVirtual
77  private val memIsVirt   = current.dMode.isVirtual
78
79  private val isFetchExcp    = isException && ExceptionNO.getFetchFault.map(_.U === highPrioTrapNO).reduce(_ || _)
80  private val isMemExcp      = isException && (ExceptionNO.getLoadFault ++ ExceptionNO.getStoreFault).map(_.U === highPrioTrapNO).reduce(_ || _)
81  private val isBpExcp       = isException && ExceptionNO.EX_BP.U === highPrioTrapNO
82  private val isHlsExcp      = isException && in.isHls
83  private val fetchCrossPage = in.isCrossPageIPF
84  private val isIllegalInst  = isException && (ExceptionNO.EX_II.U === highPrioTrapNO || ExceptionNO.EX_VI.U === highPrioTrapNO)
85
86  private val isLSGuestExcp    = isException && ExceptionNO.getLSGuestPageFault.map(_.U === highPrioTrapNO).reduce(_ || _)
87  private val isFetchGuestExcp = isException && ExceptionNO.EX_IGPF.U === highPrioTrapNO
88  // Software breakpoint exceptions are permitted to write either 0 or the pc to xtval
89  // We fill pc here
90  private val tvalFillPc       = (isFetchExcp || isFetchGuestExcp) && !fetchCrossPage || isBpExcp
91  private val tvalFillPcPlus2  = (isFetchExcp || isFetchGuestExcp) && fetchCrossPage
92  private val tvalFillMemVaddr = isMemExcp
93  private val tvalFillGVA      =
94    isHlsExcp && isMemExcp ||
95    isLSGuestExcp|| isFetchGuestExcp ||
96    (isFetchExcp || isBpExcp) && fetchIsVirt ||
97    isMemExcp && memIsVirt
98  private val tvalFillInst     = isIllegalInst
99
100  private val tval = Mux1H(Seq(
101    (tvalFillPc                     ) -> trapPC,
102    (tvalFillPcPlus2                ) -> (trapPC + 2.U),
103    (tvalFillMemVaddr && !memIsVirt ) -> trapMemVA,
104    (tvalFillMemVaddr &&  memIsVirt ) -> trapMemVA,
105    (isLSGuestExcp                  ) -> trapMemVA,
106    (tvalFillInst                   ) -> trapInst,
107  ))
108
109  private val tval2 = Mux1H(Seq(
110    (isFetchGuestExcp && !fetchCrossPage) -> trapPCGPA,
111    (isFetchGuestExcp && fetchCrossPage ) -> (trapPCGPA + 2.U),
112    (isLSGuestExcp                      ) -> trapMemGPA,
113  ))
114
115  out := DontCare
116
117  out.privState.valid := valid
118  out.mstatus  .valid := valid
119  out.hstatus  .valid := valid
120  out.sepc     .valid := valid
121  out.scause   .valid := valid
122  out.stval    .valid := valid
123  out.htval    .valid := valid
124  out.htinst   .valid := valid
125  out.targetPc .valid := valid
126
127  out.privState.bits            := PrivState.ModeHS
128  // mstatus
129  out.mstatus.bits.SPP          := current.privState.PRVM.asUInt(0, 0) // SPP is not PrivMode enum type, so asUInt and shrink the width
130  out.mstatus.bits.SPIE         := current.sstatus.SIE
131  out.mstatus.bits.SIE          := 0.U
132  // hstatus
133  out.hstatus.bits.SPV          := current.privState.V
134    // SPVP is not PrivMode enum type, so asUInt and shrink the width
135  out.hstatus.bits.SPVP         := Mux(!current.privState.isVirtual, in.hstatus.SPVP.asUInt, current.privState.PRVM.asUInt(0, 0))
136  out.hstatus.bits.GVA          := tvalFillGVA
137  out.sepc.bits.epc             := trapPC(63, 1)
138  out.scause.bits.Interrupt     := isInterrupt
139  out.scause.bits.ExceptionCode := highPrioTrapNO
140  out.stval.bits.ALL            := tval
141  out.htval.bits.ALL            := tval2 >> 2
142  out.htinst.bits.ALL           := 0.U
143  out.targetPc.bits             := in.pcFromXtvec
144
145  dontTouch(isLSGuestExcp)
146  dontTouch(tvalFillGVA)
147}
148
149trait TrapEntryHSEventSinkBundle { self: CSRModule[_] =>
150  val trapToHS = IO(Flipped(new TrapEntryHSEventOutput))
151
152  private val updateBundle: ValidIO[CSRBundle] = trapToHS.getBundleByName(self.modName.toLowerCase())
153
154  (reg.asInstanceOf[CSRBundle].getFields zip updateBundle.bits.getFields).foreach { case (sink, source) =>
155    if (updateBundle.bits.eventFields.contains(source)) {
156      when(updateBundle.valid) {
157        sink := source
158      }
159    }
160  }
161}
162