xref: /XiangShan/src/main/scala/xiangshan/backend/fu/NewCSR/PMPEntryModule.scala (revision 011d262c490b7fd9c718724a21daceb78ad6689a)
1package xiangshan.backend.fu.NewCSR
2
3import chisel3._
4import chisel3.util._
5import xiangshan._
6import freechips.rocketchip.rocket.CSRs
7import org.chipsalliance.cde.config.Parameters
8import xiangshan.HasPMParameters
9
10trait PMPConst extends HasPMParameters {
11  val PMPOffBits = 2 // minimal 4bytes
12  val CoarserGrain: Boolean = PlatformGrain > PMPOffBits
13}
14
15abstract class PMPBundle(implicit val p: Parameters) extends Bundle with PMPConst
16abstract class PMPModule(implicit val p: Parameters) extends Module with PMPConst
17
18class PMPEntryHandleModule(implicit p: Parameters) extends PMPModule {
19  val io = IO(new PMPEntryHandleIOBundle)
20
21  val pmpCfg   = io.in.pmpCfg
22  val pmpAddr  = io.in.pmpAddr
23
24  val ren   = io.in.ren
25  val wen   = io.in.wen
26  val addr  = io.in.addr
27  val wdata = io.in.wdata
28
29  val pmpMask  = RegInit(VecInit(Seq.fill(p(PMParameKey).NumPMP)(0.U(PMPAddrBits.W))))
30
31  val pmpEntry = Wire(Vec(p(PMParameKey).NumPMP, new PMPEntry))
32  for (i <- pmpEntry.indices) {
33    pmpEntry(i).gen(pmpCfg(i), pmpAddr(i), pmpMask(i))
34  }
35
36  // write pmpCfg
37  val cfgVec = WireInit(VecInit(Seq.fill(8)(0.U.asTypeOf(new PMPCfgBundle))))
38  for (i <- 0 until (p(PMParameKey).NumPMP/8+1) by 2) {
39    when (wen && (addr === (CSRs.pmpcfg0 + i).U)) {
40      for (j <- cfgVec.indices) {
41        val cfgOldTmp = pmpEntry(8*i/2+j).cfg
42        val cfgNewTmp = Wire(new PMPCfgBundle)
43        cfgNewTmp := wdata(8*(j+1)-1, 8*j)
44        cfgVec(j) := cfgOldTmp
45        when (!cfgOldTmp.L.asBool) {
46          cfgVec(j) := cfgNewTmp
47          cfgVec(j).W := cfgNewTmp.W.asBool && cfgNewTmp.R.asBool
48          if (CoarserGrain) {
49            cfgVec(j).A := Cat(cfgNewTmp.A.asUInt(1), cfgNewTmp.A.asUInt.orR)
50          }
51          when (PMPCfgAField.isNa4OrNapot(cfgVec(j))) {
52            pmpMask(8*i/2+j) := pmpEntry(8*i/2+j).matchMask(cfgVec(j), pmpEntry(8*i/2+j).addr.ADDRESS.asUInt)
53          }
54        }
55      }
56    }
57  }
58
59  io.out.pmpCfgWData := Cat(cfgVec.map(_.asUInt).reverse)
60
61  val pmpAddrW = Wire(Vec(p(PMParameKey).NumPMP, UInt(64.W)))
62  val pmpAddrR = Wire(Vec(p(PMParameKey).NumPMP, UInt(64.W)))
63
64  for (i <- 0 until p(PMParameKey).NumPMP) {
65    pmpAddrW(i) := pmpEntry(i).addr.ADDRESS.asUInt
66    pmpAddrR(i) := pmpEntry(i).addr.ADDRESS.asUInt
67    // write pmpAddr
68    when (wen && (addr === (CSRs.pmpaddr0 + i).U)) {
69      if (i != (p(PMParameKey).NumPMP - 1)) {
70        val addrNextLocked: Bool = PMPCfgLField.addrLocked(pmpEntry(i).cfg, pmpEntry(i + 1).cfg)
71        pmpMask(i) := Mux(!addrNextLocked, pmpEntry(i).matchMask(wdata), pmpEntry(i).mask)
72        pmpAddrW(i) := Mux(!addrNextLocked, wdata, pmpEntry(i).addr.ADDRESS.asUInt)
73      } else {
74        val addrLocked: Bool = PMPCfgLField.addrLocked(pmpEntry(i).cfg)
75        pmpMask(i) := Mux(!addrLocked, pmpEntry(i).matchMask(wdata), pmpEntry(i).mask)
76        pmpAddrW(i) := Mux(!addrLocked, wdata, pmpEntry(i).addr.ADDRESS.asUInt)
77      }
78    }
79    // read pmpAddr
80    when(ren && (addr === (CSRs.pmpaddr0 + i).U)) {
81      pmpAddrR(i) := pmpEntry(i).readAddr(pmpEntry(i).cfg, pmpEntry(i).addr.ADDRESS.asUInt)
82    }
83  }
84
85  io.out.pmpAddrWData := pmpAddrW
86  io.out.pmpAddrRData := pmpAddrR
87
88}
89
90class PMPEntryHandleIOBundle(implicit p: Parameters) extends PMPBundle {
91  val in = Input(new Bundle {
92    val wen   = Bool()
93    val ren   = Bool()
94    val addr  = UInt(12.W)
95    val wdata = UInt(64.W)
96    val pmpCfg  = Vec(NumPMP, new PMPCfgBundle)
97    val pmpAddr = Vec(NumPMP, new PMPAddrBundle)
98  })
99
100  val out = Output(new Bundle {
101    val pmpCfgWData  = UInt(PMXLEN.W)
102    val pmpAddrRData = Vec(NumPMP, UInt(64.W))
103    val pmpAddrWData = Vec(NumPMP, UInt(64.W))
104  })
105}
106
107trait PMPReadWrite extends PMPConst {
108  def matchMask(cfg: PMPCfgBundle, paddr: UInt): UInt = {
109    val matchMaskCAddr = Cat(paddr, cfg.A.asUInt(0)) | (((1 << PlatformGrain) - 1) >> PMPOffBits).U((paddr.getWidth + 1).W)
110    Cat(matchMaskCAddr & (~(matchMaskCAddr + 1.U)).asUInt, ((1 << PMPOffBits) - 1).U(PMPOffBits.W))
111  }
112
113  /**
114   * In general, the PMP grain is 2**{G+2} bytes. when G >= 1, na4 is not selectable.
115   * When G >= 2 and cfg.A(1) is set(then the mode is napot), the bits addr(G-2, 0) read as zeros.
116   * When G >= 1 and cfg.A(1) is clear(the mode is off or tor), the addr(G-1, 0) read as zeros.
117   * The low Offbits is dropped
118   * @param cfg
119   * @param addr
120   * @return
121   */
122  def readAddr(cfg: PMPCfgBundle, addr: UInt): UInt = {
123    val G = PlatformGrain - PMPOffBits
124    require(G >= 0)
125    if (G == 0) {
126      addr
127    } else if (G >= 2) {
128      Mux(PMPCfgAField.isNa4OrNapot(cfg), setLowBits(addr, G-1), clearLowBits(addr, G))
129    } else { // G is 1
130      Mux(PMPCfgAField.isOffOrTor(cfg), clearLowBits(addr, G), addr)
131    }
132  }
133
134  def setLowBits(data: UInt, num: Int): UInt = {
135    require(num >= 0)
136    data | ((1 << num)-1).U
137  }
138
139  /**
140   * mask the data's low num bits (lsb)
141   * @param data
142   * @param num
143   * @return
144   */
145  def clearLowBits(data: UInt, num: Int): UInt = {
146    require(num >= 0)
147    // use Cat instead of & with mask to avoid "Signal Width" problem
148    if (num == 0) {
149      data
150    } else {
151      Cat(data(data.getWidth - 1, num), 0.U(num.W))
152    }
153  }
154
155}
156
157/**
158 * PMPEntry for outside pmp copies with one more elements mask to help napot match
159 * TODO: make mask an element, not an method, for timing opt
160 */
161class PMPEntry(implicit p: Parameters) extends PMPBundle with PMPReadWrite {
162  val cfg  = new PMPCfgBundle
163  val addr = new PMPAddrBundle
164  val mask = UInt(PMPAddrBits.W) // help to match in napot
165
166  def gen(cfg: PMPCfgBundle, addr: PMPAddrBundle, mask: UInt) = {
167    require(addr.ADDRESS.getWidth == this.addr.ADDRESS.getWidth)
168    this.cfg := cfg
169    this.addr.ADDRESS := addr.ADDRESS
170    this.mask := mask
171  }
172
173  // generate match mask to help match in napot mode
174  def matchMask(paddr: UInt): UInt = {
175    matchMask(cfg, paddr)
176  }
177}