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