xref: /XiangShan/src/main/scala/xiangshan/backend/fu/NewCSR/CSREvents/TrapEntryHSEvent.scala (revision 25dc4a827ee27e3ccbaf02e8e5134872cba28fcd)
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, HasXSParameter}
8import xiangshan.ExceptionNO._
9import xiangshan.backend.fu.NewCSR.CSRBundles.{CauseBundle, OneFieldBundle, PrivState}
10import xiangshan.backend.fu.NewCSR.CSRConfig.{VaddrMaxWidth, XLEN}
11import xiangshan.backend.fu.NewCSR.CSRDefines.SatpMode
12import xiangshan.backend.fu.NewCSR._
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))
19  val hstatus = ValidIO((new HstatusBundle ).addInEvent(_.SPV, _.SPVP, _.GVA))
20  val sepc    = ValidIO((new Epc           ).addInEvent(_.ALL))
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(UInt(VaddrMaxWidth.W))
26
27  def getBundleByName(name: String): Valid[CSRBundle] = {
28    name match {
29      case "mstatus" => this.mstatus
30      case "hstatus" => this.hstatus
31      case "sepc"    => this.sepc
32      case "scause"  => this.scause
33      case "stval"   => this.stval
34      case "htval"   => this.htval
35      case "htinst"  => this.htinst
36    }
37  }
38}
39
40class TrapEntryHSEventModule(implicit val p: Parameters) extends Module with CSREventBase {
41  val in = IO(new TrapEntryEventInput)
42  val out = IO(new TrapEntryHSEventOutput)
43
44  private val current = in
45
46  private val highPrioTrapNO = in.causeNO.ExceptionCode.asUInt
47  private val isException = !in.causeNO.Interrupt.asBool
48  private val isInterrupt = in.causeNO.Interrupt.asBool
49
50  private val trapPC = Wire(UInt(XLEN.W))
51  private val trapMemVA = SignExt(in.memExceptionVAddr, XLEN)
52  private val trapMemGPA = SignExt(in.memExceptionGPAddr, XLEN)
53  private val ivmHS = !current.iMode.isModeHS && current.satp.MODE =/= SatpMode.Bare
54  private val ivmVS = !current.iMode.isModeVS && current.vsatp.MODE =/= SatpMode.Bare
55  // When enable virtual memory, the higher bit should fill with the msb of address of Sv39/Sv48/Sv57
56  trapPC := Mux(ivmHS || ivmVS, SignExt(in.trapPc, XLEN), ZeroExt(in.trapPc, XLEN))
57
58  private val fetchIsVirt = current.iMode.isVirtual
59  private val memIsVirt   = current.dMode.isVirtual
60
61  private val isFetchExcp    = isException && Seq(/*EX_IAM, */ EX_IAF, EX_IPF).map(_.U === highPrioTrapNO).reduce(_ || _)
62  private val isMemExcp      = isException && Seq(EX_LAM, EX_LAF, EX_SAM, EX_SAF, EX_LPF, EX_SPF).map(_.U === highPrioTrapNO).reduce(_ || _)
63  private val isBpExcp       = isException && EX_BP.U === highPrioTrapNO
64  private val fetchCrossPage = in.isCrossPageIPF
65
66  private val isGuestExcp    = isException && Seq(EX_IGPF, EX_LGPF, EX_SGPF).map(_.U === highPrioTrapNO).reduce(_ || _)
67  // Software breakpoint exceptions are permitted to write either 0 or the pc to xtval
68  // We fill pc here
69  private val tvalFillPc       = isFetchExcp && !fetchCrossPage || isBpExcp
70  private val tvalFillPcPlus2  = isFetchExcp && fetchCrossPage
71  private val tvalFillMemVaddr = isMemExcp
72  private val tvalFillGVA      = isGuestExcp ||
73    (isFetchExcp || isBpExcp) && fetchIsVirt ||
74    isMemExcp && memIsVirt
75
76  private val tval = Mux1H(Seq(
77    (tvalFillPc                     ) -> trapPC,
78    (tvalFillPcPlus2                ) -> (trapPC + 2.U),
79    (tvalFillMemVaddr && !memIsVirt ) -> trapMemVA,
80    (tvalFillMemVaddr &&  memIsVirt ) -> trapMemVA,
81    (isGuestExcp                    ) -> trapMemVA,
82  ))
83
84  private val tval2 = Mux(isGuestExcp, trapMemGPA, 0.U)
85
86  out := DontCare
87
88  out.privState.valid := valid
89  out.mstatus  .valid := valid
90  out.hstatus  .valid := valid
91  out.sepc     .valid := valid
92  out.scause   .valid := valid
93  out.stval    .valid := valid
94  out.htval    .valid := valid
95  out.targetPc .valid := valid
96
97  out.privState.bits            := PrivState.ModeHS
98  // mstatus
99  out.mstatus.bits.SPP          := current.privState.PRVM.asUInt(0, 0) // SPP is not PrivMode enum type, so asUInt and shrink the width
100  out.mstatus.bits.SPIE         := current.sstatus.SIE
101  out.mstatus.bits.SIE          := 0.U
102  // hstatus
103  out.hstatus.bits.SPV          := current.privState.V
104    // SPVP is not PrivMode enum type, so asUInt and shrink the width
105  out.hstatus.bits.SPVP         := Mux(!current.privState.isVirtual, in.hstatus.SPVP.asUInt, current.privState.PRVM.asUInt(0, 0))
106  out.hstatus.bits.GVA          := tvalFillGVA
107  out.sepc.bits.ALL             := trapPC(trapPC.getWidth - 1, 1)
108  out.scause.bits.Interrupt     := isInterrupt
109  out.scause.bits.ExceptionCode := highPrioTrapNO
110  out.stval.bits.ALL            := tval
111  out.htval.bits.ALL            := tval2
112  out.htinst.bits.ALL           := 0.U
113  out.targetPc.bits             := in.pcFromXtvec
114
115  dontTouch(isGuestExcp)
116  dontTouch(tvalFillGVA)
117}
118
119trait TrapEntryHSEventSinkBundle { self: CSRModule[_] =>
120  val trapToHS = IO(Flipped(new TrapEntryHSEventOutput))
121
122  private val updateBundle: ValidIO[CSRBundle] = trapToHS.getBundleByName(self.modName.toLowerCase())
123
124  (reg.asInstanceOf[CSRBundle].getFields zip updateBundle.bits.getFields).foreach { case (sink, source) =>
125    if (updateBundle.bits.eventFields.contains(source)) {
126      when(updateBundle.valid) {
127        sink := source
128      }
129    }
130  }
131}
132