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