xref: /XiangShan/src/main/scala/xiangshan/backend/fu/CSR.scala (revision 304b8afd7e3ffbbfd202fee36adef0cdf40018e7)
1package xiangshan.backend.fu
2
3import chisel3._
4import chisel3.ExcitingUtils.ConnectionType
5import chisel3.util._
6import chisel3.util.experimental.BoringUtils
7import fpu.Fflags
8import noop.MMUIO
9import utils._
10import xiangshan._
11import xiangshan.backend._
12import xiangshan.backend.fu.FunctionUnit._
13import utils.XSDebug
14
15trait HasCSRConst {
16  // User Trap Setup
17  val Ustatus       = 0x000
18  val Uie           = 0x004
19  val Utvec         = 0x005
20
21  // User Trap Handling
22  val Uscratch      = 0x040
23  val Uepc          = 0x041
24  val Ucause        = 0x042
25  val Utval         = 0x043
26  val Uip           = 0x044
27
28  // User Floating-Point CSRs (not implemented)
29  val Fflags        = 0x001
30  val Frm           = 0x002
31  val Fcsr          = 0x003
32
33  // User Counter/Timers
34  val Cycle         = 0xC00
35  val Time          = 0xC01
36  val Instret       = 0xC02
37
38  // Supervisor Trap Setup
39  val Sstatus       = 0x100
40  val Sedeleg       = 0x102
41  val Sideleg       = 0x103
42  val Sie           = 0x104
43  val Stvec         = 0x105
44  val Scounteren    = 0x106
45
46  // Supervisor Trap Handling
47  val Sscratch      = 0x140
48  val Sepc          = 0x141
49  val Scause        = 0x142
50  val Stval         = 0x143
51  val Sip           = 0x144
52
53  // Supervisor Protection and Translation
54  val Satp          = 0x180
55
56  // Machine Information Registers
57  val Mvendorid     = 0xF11
58  val Marchid       = 0xF12
59  val Mimpid        = 0xF13
60  val Mhartid       = 0xF14
61
62  // Machine Trap Setup
63  val Mstatus       = 0x300
64  val Misa          = 0x301
65  val Medeleg       = 0x302
66  val Mideleg       = 0x303
67  val Mie           = 0x304
68  val Mtvec         = 0x305
69  val Mcounteren    = 0x306
70
71  // Machine Trap Handling
72  val Mscratch      = 0x340
73  val Mepc          = 0x341
74  val Mcause        = 0x342
75  val Mtval         = 0x343
76  val Mip           = 0x344
77
78  // Machine Memory Protection
79  // TBD
80  val Pmpcfg0       = 0x3A0
81  val Pmpcfg1       = 0x3A1
82  val Pmpcfg2       = 0x3A2
83  val Pmpcfg3       = 0x3A3
84  val PmpaddrBase   = 0x3B0
85
86  // Machine Counter/Timers
87  // Currently, we uses perfcnt csr set instead of standard Machine Counter/Timers
88  // 0xB80 - 0x89F are also used as perfcnt csr
89
90  // Machine Counter Setup (not implemented)
91  // Debug/Trace Registers (shared with Debug Mode) (not implemented)
92  // Debug Mode Registers (not implemented)
93
94  def privEcall  = 0x000.U
95  def privEbreak = 0x001.U
96  def privMret   = 0x302.U
97  def privSret   = 0x102.U
98  def privUret   = 0x002.U
99
100  def ModeM     = 0x3.U
101  def ModeH     = 0x2.U
102  def ModeS     = 0x1.U
103  def ModeU     = 0x0.U
104
105  def IRQ_UEIP  = 0
106  def IRQ_SEIP  = 1
107  def IRQ_MEIP  = 3
108
109  def IRQ_UTIP  = 4
110  def IRQ_STIP  = 5
111  def IRQ_MTIP  = 7
112
113  def IRQ_USIP  = 8
114  def IRQ_SSIP  = 9
115  def IRQ_MSIP  = 11
116
117  val IntPriority = Seq(
118    IRQ_MEIP, IRQ_MSIP, IRQ_MTIP,
119    IRQ_SEIP, IRQ_SSIP, IRQ_STIP,
120    IRQ_UEIP, IRQ_USIP, IRQ_UTIP
121  )
122
123  def csrAccessPermissionCheck(addr: UInt, wen: Bool, mode: UInt): Bool = {
124    val readOnly = addr(11,10) === "b11".U
125    val lowestAccessPrivilegeLevel = addr(9,8)
126    mode >= lowestAccessPrivilegeLevel && !(wen && readOnly)
127  }
128}
129
130trait HasExceptionNO {
131  def instrAddrMisaligned = 0
132  def instrAccessFault    = 1
133  def illegalInstr        = 2
134  def breakPoint          = 3
135  def loadAddrMisaligned  = 4
136  def loadAccessFault     = 5
137  def storeAddrMisaligned = 6
138  def storeAccessFault    = 7
139  def ecallU              = 8
140  def ecallS              = 9
141  def ecallM              = 11
142  def instrPageFault      = 12
143  def loadPageFault       = 13
144  def storePageFault      = 15
145
146  val ExcPriority = Seq(
147      breakPoint, // TODO: different BP has different priority
148      instrPageFault,
149      instrAccessFault,
150      illegalInstr,
151      instrAddrMisaligned,
152      ecallM, ecallS, ecallU,
153      storePageFault,
154      loadPageFault,
155      storeAccessFault,
156      loadAccessFault,
157      storeAddrMisaligned,
158      loadAddrMisaligned
159  )
160}
161
162class FpuCsrIO extends XSBundle {
163  val fflags = Output(new Fflags)
164  val isIllegal = Output(Bool())
165  val dirty_fs = Output(Bool())
166  val frm = Input(UInt(3.W))
167}
168
169class CSRIO extends FunctionUnitIO[UInt, Null](csrCfg, len=64, extIn= FuOpType()) {
170
171  val cfIn = Input(new CtrlFlow)
172  val redirectOut = Output(new Redirect)
173  val redirectOutValid = Output(Bool())
174  val fpu_csr = Flipped(new FpuCsrIO)
175  val cfOut = Output(new CtrlFlow)
176  // from rob
177  val exception = Flipped(ValidIO(new MicroOp))
178  // for exception check
179  val instrValid = Input(Bool())
180  val flushPipe = Output(Bool())
181  // for differential testing
182//  val intrNO = Output(UInt(XLEN.W))
183  val wenFix = Output(Bool())
184
185  override def cloneType: CSRIO.this.type =
186    new CSRIO().asInstanceOf[this.type]
187
188}
189
190class CSR extends XSModule
191    with HasCSRConst
192{
193
194  val io = IO(new CSRIO)
195
196  io.cfOut := io.cfIn
197
198  val (valid, src1, src2, func) =
199    (io.in.valid, io.in.bits.src(0), io.in.bits.uop.ctrl.imm, io.in.bits.ext.get)
200
201  // CSR define
202
203  class Priv extends Bundle {
204    val m = Output(Bool())
205    val h = Output(Bool())
206    val s = Output(Bool())
207    val u = Output(Bool())
208  }
209
210  val csrNotImplemented = RegInit(UInt(XLEN.W), 0.U)
211
212  class MstatusStruct extends Bundle {
213    val sd = Output(UInt(1.W))
214
215    val pad1 = if (XLEN == 64) Output(UInt(27.W)) else null
216    val sxl  = if (XLEN == 64) Output(UInt(2.W))  else null
217    val uxl  = if (XLEN == 64) Output(UInt(2.W))  else null
218    val pad0 = if (XLEN == 64) Output(UInt(9.W))  else Output(UInt(8.W))
219
220    val tsr = Output(UInt(1.W))
221    val tw = Output(UInt(1.W))
222    val tvm = Output(UInt(1.W))
223    val mxr = Output(UInt(1.W))
224    val sum = Output(UInt(1.W))
225    val mprv = Output(UInt(1.W))
226    val xs = Output(UInt(2.W))
227    val fs = Output(UInt(2.W))
228    val mpp = Output(UInt(2.W))
229    val hpp = Output(UInt(2.W))
230    val spp = Output(UInt(1.W))
231    val pie = new Priv
232    val ie = new Priv
233    assert(this.getWidth == XLEN)
234  }
235
236  class SatpStruct extends Bundle {
237    val mode = UInt(4.W)
238    val asid = UInt(16.W)
239    val ppn  = UInt(44.W)
240  }
241
242  class Interrupt extends Bundle {
243    val e = new Priv
244    val t = new Priv
245    val s = new Priv
246  }
247
248  // Machine-Level CSRs
249
250  val mtvec = RegInit(UInt(XLEN.W), 0.U)
251  val mcounteren = RegInit(UInt(XLEN.W), 0.U)
252  val mcause = RegInit(UInt(XLEN.W), 0.U)
253  val mtval = RegInit(UInt(XLEN.W), 0.U)
254  val mepc = Reg(UInt(XLEN.W))
255
256  val mie = RegInit(0.U(XLEN.W))
257  val mipWire = WireInit(0.U.asTypeOf(new Interrupt))
258  val mipReg  = RegInit(0.U.asTypeOf(new Interrupt).asUInt)
259  val mipFixMask = GenMask(9) | GenMask(5) | GenMask(1)
260  val mip = (mipWire.asUInt | mipReg).asTypeOf(new Interrupt)
261
262  def getMisaMxl(mxl: Int): UInt = {mxl.U << (XLEN-2)}.asUInt()
263  def getMisaExt(ext: Char): UInt = {1.U << (ext.toInt - 'a'.toInt)}.asUInt()
264  var extList = List('a', 's', 'i', 'u')
265  if(HasMExtension){ extList = extList :+ 'm'}
266  if(HasCExtension){ extList = extList :+ 'c'}
267  if(HasFPU){ extList = extList ++ List('f', 'd')}
268  val misaInitVal = getMisaMxl(2) | extList.foldLeft(0.U)((sum, i) => sum | getMisaExt(i)) //"h8000000000141105".U
269  val misa = RegInit(UInt(XLEN.W), misaInitVal)
270  // MXL = 2          | 0 | EXT = b 00 0000 0100 0001 0001 0000 0101
271  // (XLEN-1, XLEN-2) |   |(25, 0)  ZY XWVU TSRQ PONM LKJI HGFE DCBA
272
273  val mvendorid = RegInit(UInt(XLEN.W), 0.U) // this is a non-commercial implementation
274  val marchid = RegInit(UInt(XLEN.W), 0.U) // return 0 to indicate the field is not implemented
275  val mimpid = RegInit(UInt(XLEN.W), 0.U) // provides a unique encoding of the version of the processor implementation
276  val mhartid = RegInit(UInt(XLEN.W), 0.U) // the hardware thread running the code
277  val mstatus = RegInit(UInt(XLEN.W), "h00001800".U)
278  // val mstatus = RegInit(UInt(XLEN.W), "h8000c0100".U)
279  // mstatus Value Table
280  // | sd   |
281  // | pad1 |
282  // | sxl  | hardlinked to 10, use 00 to pass xv6 test
283  // | uxl  | hardlinked to 00
284  // | pad0 |
285  // | tsr  |
286  // | tw   |
287  // | tvm  |
288  // | mxr  |
289  // | sum  |
290  // | mprv |
291  // | xs   | 00 |
292  // | fs   | 00 |
293  // | mpp  | 00 |
294  // | hpp  | 00 |
295  // | spp  | 0 |
296  // | pie  | 0000 | pie.h is used as UBE
297  // | ie   | 0000 | uie hardlinked to 0, as N ext is not implemented
298  val mstatusStruct = mstatus.asTypeOf(new MstatusStruct)
299  def mstatusUpdateSideEffect(mstatus: UInt): UInt = {
300    val mstatusOld = WireInit(mstatus.asTypeOf(new MstatusStruct))
301    val mstatusNew = Cat(mstatusOld.xs === "b11".U || mstatusOld.fs === "b11".U, mstatus(XLEN-2, 0))
302    mstatusNew
303  }
304
305  val mstatusMask = (~ZeroExt((
306    GenMask(XLEN-2, 38) | GenMask(31, 23) | GenMask(10, 9) | GenMask(2) |
307    GenMask(37) | // MBE
308    GenMask(36) | // SBE
309    GenMask(6)    // UBE
310  ), 64)).asUInt()
311
312  val medeleg = RegInit(UInt(XLEN.W), 0.U)
313  val mideleg = RegInit(UInt(XLEN.W), 0.U)
314  val mscratch = RegInit(UInt(XLEN.W), 0.U)
315
316  val pmpcfg0 = RegInit(UInt(XLEN.W), 0.U)
317  val pmpcfg1 = RegInit(UInt(XLEN.W), 0.U)
318  val pmpcfg2 = RegInit(UInt(XLEN.W), 0.U)
319  val pmpcfg3 = RegInit(UInt(XLEN.W), 0.U)
320  val pmpaddr0 = RegInit(UInt(XLEN.W), 0.U)
321  val pmpaddr1 = RegInit(UInt(XLEN.W), 0.U)
322  val pmpaddr2 = RegInit(UInt(XLEN.W), 0.U)
323  val pmpaddr3 = RegInit(UInt(XLEN.W), 0.U)
324
325  // Superviser-Level CSRs
326
327  // val sstatus = RegInit(UInt(XLEN.W), "h00000000".U)
328  val sstatusWmask = "hc6122".U
329  // Sstatus Write Mask
330  // -------------------------------------------------------
331  //    19           9   5     2
332  // 0  1100 0000 0001 0010 0010
333  // 0  c    0    1    2    2
334  // -------------------------------------------------------
335  val sstatusRmask = sstatusWmask | "h8000000300018000".U
336  // Sstatus Read Mask = (SSTATUS_WMASK | (0xf << 13) | (1ull << 63) | (3ull << 32))
337  val stvec = RegInit(UInt(XLEN.W), 0.U)
338  // val sie = RegInit(0.U(XLEN.W))
339  val sieMask = "h222".U & mideleg
340  val sipMask  = "h222".U & mideleg
341  val satp = RegInit(0.U(XLEN.W))
342  // val satp = RegInit(UInt(XLEN.W), "h8000000000087fbe".U) // only use for tlb naive debug
343  val satpMask = "h80000fffffffffff".U // disable asid, mode can only be 8 / 0
344  // val satp = RegInit(UInt(XLEN.W), 0.U)
345  val sepc = RegInit(UInt(XLEN.W), 0.U)
346  val scause = RegInit(UInt(XLEN.W), 0.U)
347  val stval = Reg(UInt(XLEN.W))
348  val sscratch = RegInit(UInt(XLEN.W), 0.U)
349  val scounteren = RegInit(UInt(XLEN.W), 0.U)
350
351  val tlbBundle = Wire(new TlbCsrBundle)
352  // val sfence    = Wire(new SfenceBundle)
353  tlbBundle.satp := satp.asTypeOf(new SatpStruct)
354  // sfence := 0.U.asTypeOf(new SfenceBundle)
355  BoringUtils.addSource(tlbBundle, "TLBCSRIO")
356  // BoringUtils.addSource(sfence, "SfenceBundle") // FIXME: move to MOU
357
358  // User-Level CSRs
359  val uepc = Reg(UInt(XLEN.W))
360
361  // fcsr
362  class FcsrStruct extends Bundle{
363    val reserved = UInt((XLEN-3-5).W)
364    val frm = UInt(3.W)
365    val fflags = UInt(5.W)
366    assert(this.getWidth == XLEN)
367  }
368  val fcsr = RegInit(0.U(XLEN.W))
369  // set mstatus->sd and mstatus->fs when true
370  val csrw_dirty_fp_state = WireInit(false.B)
371
372  def frm_wfn(wdata: UInt): UInt = {
373    val fcsrOld = WireInit(fcsr.asTypeOf(new FcsrStruct))
374    csrw_dirty_fp_state := true.B
375    fcsrOld.frm := wdata(2,0)
376    fcsrOld.asUInt()
377  }
378  def frm_rfn(rdata: UInt): UInt = rdata(7,5)
379
380  def fflags_wfn(wdata: UInt): UInt = {
381    val fcsrOld = WireInit(fcsr.asTypeOf(new FcsrStruct))
382    csrw_dirty_fp_state := true.B
383    fcsrOld.fflags := wdata(4,0)
384    fcsrOld.asUInt()
385  }
386  def fflags_rfn(rdata:UInt): UInt = rdata(4,0)
387
388  def fcsr_wfn(wdata: UInt): UInt = {
389    val fcsrOld = WireInit(fcsr.asTypeOf(new FcsrStruct))
390    csrw_dirty_fp_state := true.B
391    Cat(fcsrOld.reserved, wdata.asTypeOf(fcsrOld).frm, wdata.asTypeOf(fcsrOld).fflags)
392  }
393
394  val fcsrMapping = Map(
395    MaskedRegMap(Fflags, fcsr, wfn = fflags_wfn, rfn = fflags_rfn),
396    MaskedRegMap(Frm, fcsr, wfn = frm_wfn, rfn = frm_rfn),
397    MaskedRegMap(Fcsr, fcsr, wfn = fcsr_wfn)
398  )
399
400  // Atom LR/SC Control Bits
401//  val setLr = WireInit(Bool(), false.B)
402//  val setLrVal = WireInit(Bool(), false.B)
403//  val setLrAddr = WireInit(UInt(AddrBits.W), DontCare) //TODO : need check
404//  val lr = RegInit(Bool(), false.B)
405//  val lrAddr = RegInit(UInt(AddrBits.W), 0.U)
406//  BoringUtils.addSink(setLr, "set_lr")
407//  BoringUtils.addSink(setLrVal, "set_lr_val")
408//  BoringUtils.addSink(setLrAddr, "set_lr_addr")
409//  BoringUtils.addSource(lr, "lr")
410//  BoringUtils.addSource(lrAddr, "lr_addr")
411//
412//  when(setLr){
413//    lr := setLrVal
414//    lrAddr := setLrAddr
415//  }
416
417  // Hart Priviledge Mode
418  val priviledgeMode = RegInit(UInt(2.W), ModeM)
419
420  // perfcnt
421  val hasPerfCnt = !env.FPGAPlatform
422  val nrPerfCnts = if (hasPerfCnt) 0x80 else 0x3
423  val perfCnts = List.fill(nrPerfCnts)(RegInit(0.U(XLEN.W)))
424  val perfCntsLoMapping = (0 until nrPerfCnts).map(i => MaskedRegMap(0xb00 + i, perfCnts(i)))
425  val perfCntsHiMapping = (0 until nrPerfCnts).map(i => MaskedRegMap(0xb80 + i, perfCnts(i)(63, 32)))
426
427  // CSR reg map
428  val mapping = Map(
429
430    // User Trap Setup
431    // MaskedRegMap(Ustatus, ustatus),
432    // MaskedRegMap(Uie, uie, 0.U, MaskedRegMap.Unwritable),
433    // MaskedRegMap(Utvec, utvec),
434
435    // User Trap Handling
436    // MaskedRegMap(Uscratch, uscratch),
437    // MaskedRegMap(Uepc, uepc),
438    // MaskedRegMap(Ucause, ucause),
439    // MaskedRegMap(Utval, utval),
440    // MaskedRegMap(Uip, uip),
441
442    // User Counter/Timers
443    // MaskedRegMap(Cycle, cycle),
444    // MaskedRegMap(Time, time),
445    // MaskedRegMap(Instret, instret),
446
447    // Supervisor Trap Setup
448    MaskedRegMap(Sstatus, mstatus, sstatusWmask, mstatusUpdateSideEffect, sstatusRmask),
449
450    // MaskedRegMap(Sedeleg, Sedeleg),
451    // MaskedRegMap(Sideleg, Sideleg),
452    MaskedRegMap(Sie, mie, sieMask, MaskedRegMap.NoSideEffect, sieMask),
453    MaskedRegMap(Stvec, stvec),
454    MaskedRegMap(Scounteren, scounteren),
455
456    // Supervisor Trap Handling
457    MaskedRegMap(Sscratch, sscratch),
458    MaskedRegMap(Sepc, sepc),
459    MaskedRegMap(Scause, scause),
460    MaskedRegMap(Stval, stval),
461    MaskedRegMap(Sip, mip.asUInt, sipMask, MaskedRegMap.Unwritable, sipMask),
462
463    // Supervisor Protection and Translation
464    MaskedRegMap(Satp, satp, satpMask, MaskedRegMap.NoSideEffect, satpMask),
465
466    // Machine Information Registers
467    MaskedRegMap(Mvendorid, mvendorid, 0.U, MaskedRegMap.Unwritable),
468    MaskedRegMap(Marchid, marchid, 0.U, MaskedRegMap.Unwritable),
469    MaskedRegMap(Mimpid, mimpid, 0.U, MaskedRegMap.Unwritable),
470    MaskedRegMap(Mhartid, mhartid, 0.U, MaskedRegMap.Unwritable),
471
472    // Machine Trap Setup
473    // MaskedRegMap(Mstatus, mstatus, "hffffffffffffffee".U, (x=>{printf("mstatus write: %x time: %d\n", x, GTimer()); x})),
474    MaskedRegMap(Mstatus, mstatus, mstatusMask, mstatusUpdateSideEffect, mstatusMask),
475    MaskedRegMap(Misa, misa), // now MXL, EXT is not changeable
476    MaskedRegMap(Medeleg, medeleg, "hf3ff".U),
477    MaskedRegMap(Mideleg, mideleg, "h222".U),
478    MaskedRegMap(Mie, mie),
479    MaskedRegMap(Mtvec, mtvec),
480    MaskedRegMap(Mcounteren, mcounteren),
481
482    // Machine Trap Handling
483    MaskedRegMap(Mscratch, mscratch),
484    MaskedRegMap(Mepc, mepc),
485    MaskedRegMap(Mcause, mcause),
486    MaskedRegMap(Mtval, mtval),
487    MaskedRegMap(Mip, mip.asUInt, 0.U, MaskedRegMap.Unwritable),
488
489    // Machine Memory Protection
490    MaskedRegMap(Pmpcfg0, pmpcfg0),
491    MaskedRegMap(Pmpcfg1, pmpcfg1),
492    MaskedRegMap(Pmpcfg2, pmpcfg2),
493    MaskedRegMap(Pmpcfg3, pmpcfg3),
494    MaskedRegMap(PmpaddrBase + 0, pmpaddr0),
495    MaskedRegMap(PmpaddrBase + 1, pmpaddr1),
496    MaskedRegMap(PmpaddrBase + 2, pmpaddr2),
497    MaskedRegMap(PmpaddrBase + 3, pmpaddr3)
498
499  ) ++
500    perfCntsLoMapping ++ (if (XLEN == 32) perfCntsHiMapping else Nil) ++
501    (if(HasFPU) fcsrMapping else Nil)
502
503  val addr = src2(11, 0)
504  val rdata = Wire(UInt(XLEN.W))
505  val csri = ZeroExt(io.cfIn.instr(19,15), XLEN) //unsigned imm for csri. [TODO]
506  val wdata = LookupTree(func, List(
507    CSROpType.wrt  -> src1,
508    CSROpType.set  -> (rdata | src1),
509    CSROpType.clr  -> (rdata & (~src1).asUInt()),
510    CSROpType.wrti -> csri,//TODO: csri --> src2
511    CSROpType.seti -> (rdata | csri),
512    CSROpType.clri -> (rdata & (~csri).asUInt())
513  ))
514
515  // satp wen check
516  val satpLegalMode = (wdata.asTypeOf(new SatpStruct).mode===0.U) || (wdata.asTypeOf(new SatpStruct).mode===8.U)
517
518  // general CSR wen check
519  val wen = valid && func =/= CSROpType.jmp && (addr=/=Satp.U || satpLegalMode)
520  val permitted = csrAccessPermissionCheck(addr, false.B, priviledgeMode)
521  // Writeable check is ingored.
522  // Currently, write to illegal csr addr will be ignored
523  MaskedRegMap.generate(mapping, addr, rdata, wen && permitted, wdata)
524  io.out.bits.data := rdata
525  io.out.bits.uop := io.in.bits.uop
526
527  // Fix Mip/Sip write
528  val fixMapping = Map(
529    MaskedRegMap(Mip, mipReg.asUInt, mipFixMask),
530    MaskedRegMap(Sip, mipReg.asUInt, sipMask, MaskedRegMap.NoSideEffect, sipMask)
531  )
532  val rdataDummy = Wire(UInt(XLEN.W))
533  MaskedRegMap.generate(fixMapping, addr, rdataDummy, wen, wdata)
534
535  when(io.fpu_csr.fflags.asUInt() =/= 0.U){
536    fcsr := fflags_wfn(io.fpu_csr.fflags.asUInt())
537  }
538  // set fs and sd in mstatus
539  when(csrw_dirty_fp_state || io.fpu_csr.dirty_fs){
540    val mstatusNew = WireInit(mstatus.asTypeOf(new MstatusStruct))
541    mstatusNew.fs := "b11".U
542    mstatusNew.sd := true.B
543    mstatus := mstatusNew.asUInt()
544  }
545  io.fpu_csr.frm := fcsr.asTypeOf(new FcsrStruct).frm
546
547  // CSR inst decode
548  val isEbreak = addr === privEbreak && func === CSROpType.jmp
549  val isEcall = addr === privEcall && func === CSROpType.jmp
550  val isMret = addr === privMret   && func === CSROpType.jmp
551  val isSret = addr === privSret   && func === CSROpType.jmp
552  val isUret = addr === privUret   && func === CSROpType.jmp
553
554  XSDebug(wen, "csr write: pc %x addr %x rdata %x wdata %x func %x\n", io.cfIn.pc, addr, rdata, wdata, func)
555  XSDebug(wen, "pc %x mstatus %x mideleg %x medeleg %x mode %x\n", io.cfIn.pc, mstatus, mideleg , medeleg, priviledgeMode)
556
557  // Illegal priviledged operation list
558  val illegalSModeSret = valid && isSret && priviledgeMode === ModeS && mstatusStruct.tsr.asBool
559
560  // Illegal priviledged instruction check
561  val isIllegalAddr = MaskedRegMap.isIllegalAddr(mapping, addr)
562  val isIllegalAccess = !permitted
563  val isIllegalPrivOp = illegalSModeSret
564
565  // def MMUPermissionCheck(ptev: Bool, pteu: Bool): Bool = ptev && !(priviledgeMode === ModeU && !pteu) && !(priviledgeMode === ModeS && pteu && mstatusStruct.sum.asBool)
566  // def MMUPermissionCheckLoad(ptev: Bool, pteu: Bool): Bool = ptev && !(priviledgeMode === ModeU && !pteu) && !(priviledgeMode === ModeS && pteu && mstatusStruct.sum.asBool) && (pter || (mstatusStruct.mxr && ptex))
567  // imem
568  // val imemPtev = true.B
569  // val imemPteu = true.B
570  // val imemPtex = true.B
571  // val imemReq = true.B
572  // val imemPermissionCheckPassed = MMUPermissionCheck(imemPtev, imemPteu)
573  // val hasInstrPageFault = imemReq && !(imemPermissionCheckPassed && imemPtex)
574  // assert(!hasInstrPageFault)
575
576  // dmem
577  // val dmemPtev = true.B
578  // val dmemPteu = true.B
579  // val dmemReq = true.B
580  // val dmemPermissionCheckPassed = MMUPermissionCheck(dmemPtev, dmemPteu)
581  // val dmemIsStore = true.B
582
583  // val hasLoadPageFault  = dmemReq && !dmemIsStore && !(dmemPermissionCheckPassed)
584  // val hasStorePageFault = dmemReq &&  dmemIsStore && !(dmemPermissionCheckPassed)
585  // assert(!hasLoadPageFault)
586  // assert(!hasStorePageFault)
587
588  //TODO: Havn't test if io.dmemMMU.priviledgeMode is correct yet
589  tlbBundle.priv.mxr   := mstatusStruct.mxr.asBool
590  tlbBundle.priv.sum   := mstatusStruct.sum.asBool
591  tlbBundle.priv.imode := priviledgeMode
592  tlbBundle.priv.dmode := Mux(mstatusStruct.mprv.asBool, mstatusStruct.mpp, priviledgeMode)
593
594  val hasInstrPageFault = io.exception.bits.cf.exceptionVec(instrPageFault) && io.exception.valid
595  val hasLoadPageFault = io.exception.bits.cf.exceptionVec(loadPageFault) && io.exception.valid
596  val hasStorePageFault = io.exception.bits.cf.exceptionVec(storePageFault) && io.exception.valid
597  val hasStoreAddrMisaligned = io.exception.bits.cf.exceptionVec(storeAddrMisaligned) && io.exception.valid
598  val hasLoadAddrMisaligned = io.exception.bits.cf.exceptionVec(loadAddrMisaligned) && io.exception.valid
599
600  // mtval write logic
601  val memExceptionAddr = WireInit(0.U(VAddrBits.W))
602  ExcitingUtils.addSource(io.exception.bits.lsroqIdx, "EXECPTION_LSROQIDX")
603  ExcitingUtils.addSink(memExceptionAddr, "EXECPTION_VADDR")
604  when(hasInstrPageFault || hasLoadPageFault || hasStorePageFault){
605    val tval = Mux(
606      hasInstrPageFault,
607      Mux(
608        io.exception.bits.cf.crossPageIPFFix,
609        SignExt(io.exception.bits.cf.pc + 2.U, XLEN),
610        SignExt(io.exception.bits.cf.pc, XLEN)
611      ),
612      SignExt(memExceptionAddr, XLEN)
613    )
614    when(priviledgeMode === ModeM){
615      mtval := tval
616    }.otherwise{
617      stval := tval
618    }
619  }
620
621  when(hasLoadAddrMisaligned || hasStoreAddrMisaligned)
622  {
623    mtval := SignExt(memExceptionAddr, XLEN)
624  }
625
626  // Exception and Intr
627
628  // interrupts
629
630  val ideleg =  (mideleg & mip.asUInt)
631  def priviledgedEnableDetect(x: Bool): Bool = Mux(x, ((priviledgeMode === ModeS) && mstatusStruct.ie.s) || (priviledgeMode < ModeS),
632    ((priviledgeMode === ModeM) && mstatusStruct.ie.m) || (priviledgeMode < ModeM))
633
634  val intrVecEnable = Wire(Vec(12, Bool()))
635  intrVecEnable.zip(ideleg.asBools).map{case(x,y) => x := priviledgedEnableDetect(y)}
636  val intrVec = mie(11,0) & mip.asUInt & intrVecEnable.asUInt
637  val intrBitSet = intrVec.orR()
638  ExcitingUtils.addSource(intrBitSet, "intrBitSetIDU")
639  val intrNO = IntPriority.foldRight(0.U)((i: Int, sum: UInt) => Mux(intrVec(i), i.U, sum))
640  val raiseIntr = intrBitSet && io.exception.valid
641  XSDebug(raiseIntr, "interrupt: pc=0x%x, %d\n", io.exception.bits.cf.pc, intrNO)
642
643  val mtip = WireInit(false.B)
644  val msip = WireInit(false.B)
645  val meip = WireInit(false.B)
646  ExcitingUtils.addSink(mtip, "mtip")
647  ExcitingUtils.addSink(msip, "msip")
648  ExcitingUtils.addSink(meip, "meip")
649  mipWire.t.m := mtip
650  mipWire.s.m := msip
651  mipWire.e.m := meip
652
653  // exceptions
654  val csrExceptionVec = Wire(Vec(16, Bool()))
655  csrExceptionVec.map(_ := false.B)
656  csrExceptionVec(breakPoint) := io.in.valid && isEbreak
657  csrExceptionVec(ecallM) := priviledgeMode === ModeM && io.in.valid && isEcall
658  csrExceptionVec(ecallS) := priviledgeMode === ModeS && io.in.valid && isEcall
659  csrExceptionVec(ecallU) := priviledgeMode === ModeU && io.in.valid && isEcall
660  // Trigger an illegal instr exception when:
661  // * unimplemented csr is being read/written
662  // * csr access is illegal
663  csrExceptionVec(illegalInstr) := (isIllegalAddr || isIllegalAccess) && wen
664  csrExceptionVec(loadPageFault) := hasLoadPageFault
665  csrExceptionVec(storePageFault) := hasStorePageFault
666  val iduExceptionVec = io.cfIn.exceptionVec
667  val exceptionVec = csrExceptionVec.asUInt() | iduExceptionVec.asUInt()
668  io.cfOut.exceptionVec.zipWithIndex.map{case (e, i) => e := exceptionVec(i) }
669  io.wenFix := DontCare
670
671  val raiseExceptionVec = io.exception.bits.cf.exceptionVec.asUInt()
672  val exceptionNO = ExcPriority.foldRight(0.U)((i: Int, sum: UInt) => Mux(raiseExceptionVec(i), i.U, sum))
673  val causeNO = (raiseIntr << (XLEN-1)).asUInt() | Mux(raiseIntr, intrNO, exceptionNO)
674  val difftestIntrNO = Mux(raiseIntr, causeNO, 0.U)
675  ExcitingUtils.addSource(difftestIntrNO, "difftestIntrNOfromCSR")
676
677  val raiseExceptionIntr = io.exception.valid
678  val retTarget = Wire(UInt(VAddrBits.W))
679  val trapTarget = Wire(UInt(VAddrBits.W))
680  ExcitingUtils.addSource(trapTarget, "trapTarget")
681  val resetSatp = addr === Satp.U && wen // write to satp will cause the pipeline be flushed
682  io.redirectOut := DontCare
683  io.redirectOutValid := valid && func === CSROpType.jmp && !isEcall
684  io.redirectOut.target := retTarget
685  io.flushPipe := resetSatp
686
687  XSDebug(io.redirectOutValid, "redirect to %x, pc=%x\n", io.redirectOut.target, io.cfIn.pc)
688
689  XSDebug(raiseExceptionIntr, "int/exc: pc %x int (%d):%x exc: (%d):%x\n",io.exception.bits.cf.pc, intrNO, io.exception.bits.cf.intrVec.asUInt, exceptionNO, raiseExceptionVec.asUInt)
690  XSDebug(raiseExceptionIntr, "pc %x mstatus %x mideleg %x medeleg %x mode %x\n", io.exception.bits.cf.pc, mstatus, mideleg, medeleg, priviledgeMode)
691
692  // Branch control
693
694  val deleg = Mux(raiseIntr, mideleg , medeleg)
695  // val delegS = ((deleg & (1 << (causeNO & 0xf))) != 0) && (priviledgeMode < ModeM);
696  val delegS = (deleg(causeNO(3,0))) && (priviledgeMode < ModeM)
697  val tvalWen = !(hasInstrPageFault || hasLoadPageFault || hasStorePageFault || hasLoadAddrMisaligned || hasStoreAddrMisaligned) || raiseIntr // TODO: need check
698
699  trapTarget := Mux(delegS, stvec, mtvec)(VAddrBits-1, 0)
700  retTarget := DontCare
701  // val illegalEret = TODO
702
703  when (valid && isMret) {
704    val mstatusOld = WireInit(mstatus.asTypeOf(new MstatusStruct))
705    val mstatusNew = WireInit(mstatus.asTypeOf(new MstatusStruct))
706    mstatusNew.ie.m := mstatusOld.pie.m
707    priviledgeMode := mstatusOld.mpp
708    mstatusNew.pie.m := true.B
709    mstatusNew.mpp := ModeU
710    mstatusNew.mprv := 0.U
711    mstatus := mstatusNew.asUInt
712//    lr := false.B
713    retTarget := mepc(VAddrBits-1, 0)
714  }
715
716  when (valid && isSret && !illegalSModeSret) {
717    val mstatusOld = WireInit(mstatus.asTypeOf(new MstatusStruct))
718    val mstatusNew = WireInit(mstatus.asTypeOf(new MstatusStruct))
719    mstatusNew.ie.s := mstatusOld.pie.s
720    priviledgeMode := Cat(0.U(1.W), mstatusOld.spp)
721    mstatusNew.pie.s := true.B
722    mstatusNew.spp := ModeU
723    mstatus := mstatusNew.asUInt
724    mstatusNew.mprv := 0.U
725    // lr := false.B
726    retTarget := sepc(VAddrBits-1, 0)
727  }
728
729  when (valid && isUret) {
730    val mstatusOld = WireInit(mstatus.asTypeOf(new MstatusStruct))
731    val mstatusNew = WireInit(mstatus.asTypeOf(new MstatusStruct))
732    // mstatusNew.mpp.m := ModeU //TODO: add mode U
733    mstatusNew.ie.u := mstatusOld.pie.u
734    priviledgeMode := ModeU
735    mstatusNew.pie.u := true.B
736    mstatus := mstatusNew.asUInt
737    retTarget := uepc(VAddrBits-1, 0)
738  }
739
740  when (raiseExceptionIntr) {
741    val mstatusOld = WireInit(mstatus.asTypeOf(new MstatusStruct))
742    val mstatusNew = WireInit(mstatus.asTypeOf(new MstatusStruct))
743
744    when (delegS) {
745      scause := causeNO
746      sepc := SignExt(io.exception.bits.cf.pc, XLEN)
747      mstatusNew.spp := priviledgeMode
748      mstatusNew.pie.s := mstatusOld.ie.s
749      mstatusNew.ie.s := false.B
750      priviledgeMode := ModeS
751      when(tvalWen){stval := 0.U}
752      // trapTarget := stvec(VAddrBits-1. 0)
753    }.otherwise {
754      mcause := causeNO
755      mepc := SignExt(io.exception.bits.cf.pc, XLEN)
756      mstatusNew.mpp := priviledgeMode
757      mstatusNew.pie.m := mstatusOld.ie.m
758      mstatusNew.ie.m := false.B
759      priviledgeMode := ModeM
760      when(tvalWen){mtval := 0.U}
761      // trapTarget := mtvec(VAddrBits-1. 0)
762    }
763
764    mstatus := mstatusNew.asUInt
765  }
766
767  io.in.ready := true.B
768  io.out.valid := valid
769
770
771  XSDebug(io.redirectOutValid, "Rediret %x raiseExcepIntr:%d isSret:%d retTarget:%x sepc:%x delegs:%d deleg:%x cfInpc:%x valid:%d instrValid:%x \n",
772    io.redirectOut.target, raiseExceptionIntr, isSret, retTarget, sepc, delegS, deleg, io.cfIn.pc, valid, io.instrValid)
773  XSDebug(raiseExceptionIntr && delegS, "Red(%d, %x) raiseExcepIntr:%d isSret:%d retTarget:%x sepc:%x delegs:%d deleg:%x cfInpc:%x valid:%d instrValid:%x \n",
774    io.redirectOutValid, io.redirectOut.target, raiseExceptionIntr, isSret, retTarget, sepc, delegS, deleg, io.cfIn.pc, valid, io.instrValid)
775  XSDebug(raiseExceptionIntr && delegS, "sepc is writen!!! pc:%x\n", io.cfIn.pc)
776
777
778  // perfcnt
779
780  val perfCntList = Map(
781//    "Mcycle"      -> (0xb00, "perfCntCondMcycle"     ),
782//    "Minstret"    -> (0xb02, "perfCntCondMinstret"   ),
783    "MbpInstr"    -> (0xb03, "perfCntCondMbpInstr"   ),
784    "MbpRight"    -> (0xb04, "perfCntCondMbpRight"   ),
785    "MbpWrong"    -> (0xb05, "perfCntCondMbpWrong"   ),
786    "MbpBRight"   -> (0xb06, "perfCntCondMbpBRight"   ),
787    "MbpBWrong"   -> (0xb07, "perfCntCondMbpBWrong"   ),
788    "MbpJRight"   -> (0xb08, "perfCntCondMbpJRight"   ),
789    "MbpJWrong"   -> (0xb09, "perfCntCondMbpJWrong"   ),
790    "MbpIRight"   -> (0xb0a, "perfCntCondMbpIRight"   ),
791    "MbpIWrong"   -> (0xb0b, "perfCntCondMbpIWrong"   ),
792    "MbpRRight"   -> (0xb0c, "perfCntCondMbpRRight"   ),
793    "MbpRWrong"   -> (0xb0d, "perfCntCondMbpRWrong"   ),
794    "DpqReplay"   -> (0xb0e, "perfCntCondDpqReplay"   ),
795    "RoqWalk"     -> (0xb0f, "perfCntCondRoqWalk"     ),
796    "RoqWaitInt"  -> (0xb10, "perfCntCondRoqWaitInt"  ),
797    "RoqWaitFp"   -> (0xb11, "perfCntCondRoqWaitFp"   ),
798    "RoqWaitLoad" -> (0xb12, "perfCntCondRoqWaitLoad" ),
799    "RoqWaitStore"-> (0xb13, "perfCntCondRoqWaitStore"),
800    "Dp1Empty"    -> (0xb14, "perfCntCondDp1Empty"    ),
801    "DTlbReqCnt0" -> (0xb15, "perfCntDtlbReqCnt0"     ),
802    "DTlbReqCnt1" -> (0xb16, "perfCntDtlbReqCnt1"     ),
803    "DTlbReqCnt2" -> (0xb17, "perfCntDtlbReqCnt2"     ),
804    "DTlbReqCnt3" -> (0xb18, "perfCntDtlbReqCnt3"     ),
805    "DTlbMissCnt0"-> (0xb19, "perfCntDtlbMissCnt0"    ),
806    "DTlbMissCnt1"-> (0xb20, "perfCntDtlbMissCnt1"    ),
807    "DTlbMissCnt2"-> (0xb21, "perfCntDtlbMissCnt2"    ),
808    "DTlbMissCnt3"-> (0xb22, "perfCntDtlbMissCnt3"    ),
809    "ITlbReqCnt0" -> (0xb23, "perfCntItlbReqCnt0"     ),
810    "ITlbMissCnt0"-> (0xb24, "perfCntItlbMissCnt0"    ),
811    "PtwReqCnt"   -> (0xb25, "perfCntPtwReqCnt"       ),
812    "PtwCycleCnt" -> (0xb26, "perfCntPtwCycleCnt"     ),
813    "PtwL2TlbHit" -> (0xb27, "perfCntPtwL2TlbHit"     ),
814    "ICacheReq"   -> (0xb28, "perfCntIcacheReqCnt"     ),
815    "ICacheMiss"   -> (0xb29, "perfCntIcacheMissCnt"     )
816//    "Custom1"     -> (0xb1b, "Custom1"             ),
817//    "Custom2"     -> (0xb1c, "Custom2"             ),
818//    "Custom3"     -> (0xb1d, "Custom3"             ),
819//    "Custom4"     -> (0xb1e, "Custom4"             ),
820//    "Custom5"     -> (0xb1f, "Custom5"             ),
821//    "Custom6"     -> (0xb20, "Custom6"             ),
822//    "Custom7"     -> (0xb21, "Custom7"             ),
823//    "Custom8"     -> (0xb22, "Custom8"             ),
824//    "Ml2cacheHit" -> (0xb23, "perfCntCondMl2cacheHit")
825  )
826  val perfCntCond = List.fill(0x80)(WireInit(false.B))
827  (perfCnts zip perfCntCond).map { case (c, e) => when (e) { c := c + 1.U } }
828
829//  ExcitingUtils.addSource(WireInit(true.B), "perfCntCondMcycle", ConnectionType.Perf)
830  perfCntList.foreach {
831    case (_, (address, boringId)) =>
832      if(hasPerfCnt){
833        ExcitingUtils.addSink(perfCntCond(address & 0x7f), boringId, ConnectionType.Perf)
834      }
835//      if (!hasPerfCnt) {
836//        // do not enable perfcnts except for Mcycle and Minstret
837//        if (address != perfCntList("Mcycle")._1 && address != perfCntList("Minstret")._1) {
838//          perfCntCond(address & 0x7f) := false.B
839//        }
840//      }
841  }
842
843  val xstrap = WireInit(false.B)
844  if(!env.FPGAPlatform && EnableBPU){
845    ExcitingUtils.addSink(xstrap, "XSTRAP", ConnectionType.Debug)
846  }
847  def readWithScala(addr: Int): UInt = mapping(addr)._1
848
849  if (!env.FPGAPlatform) {
850
851    // display all perfcnt when nooptrap is executed
852    when (xstrap) {
853      printf("======== PerfCnt =========\n")
854      perfCntList.toSeq.sortBy(_._2._1).foreach { case (str, (address, boringId)) =>
855        printf("%d <- " + str + "\n", readWithScala(address))
856      }
857    }
858
859    // for differential testing
860//    BoringUtils.addSource(RegNext(priviledgeMode), "difftestMode")
861//    BoringUtils.addSource(RegNext(mstatus), "difftestMstatus")
862//    BoringUtils.addSource(RegNext(mstatus & sstatusRmask), "difftestSstatus")
863//    BoringUtils.addSource(RegNext(mepc), "difftestMepc")
864//    BoringUtils.addSource(RegNext(sepc), "difftestSepc")
865//    BoringUtils.addSource(RegNext(mcause), "difftestMcause")
866//    BoringUtils.addSource(RegNext(scause), "difftestScause")
867    BoringUtils.addSource(priviledgeMode, "difftestMode")
868    BoringUtils.addSource(mstatus, "difftestMstatus")
869    BoringUtils.addSource(mstatus & sstatusRmask, "difftestSstatus")
870    BoringUtils.addSource(mepc, "difftestMepc")
871    BoringUtils.addSource(sepc, "difftestSepc")
872    BoringUtils.addSource(mcause, "difftestMcause")
873    BoringUtils.addSource(scause, "difftestScause")
874    BoringUtils.addSource(satp, "difftestSatp")
875    BoringUtils.addSource(mipReg, "difftestMip")
876    BoringUtils.addSource(mie, "difftestMie")
877    BoringUtils.addSource(mscratch, "difftestMscratch")
878    BoringUtils.addSource(sscratch, "difftestSscratch")
879    BoringUtils.addSource(mideleg, "difftestMideleg")
880    BoringUtils.addSource(medeleg, "difftestMedeleg")
881  } else {
882//    BoringUtils.addSource(readWithScala(perfCntList("Minstret")._1), "ilaInstrCnt")
883  }
884}
885