xref: /XiangShan/src/main/scala/xiangshan/backend/fu/NewCSR/PMPEntryModule.scala (revision dc4fac130426dbec49b49d778b9105d79b4a8eab)
1package xiangshan.backend.fu.NewCSR
2
3import chisel3._
4import chisel3.util._
5import xiangshan._
6import org.chipsalliance.cde.config.Parameters
7import xiangshan.HasPMParameters
8
9trait PMPConst extends HasPMParameters {
10  val PMPOffBits = 2 // minimal 4bytes
11  val CoarserGrain: Boolean = PlatformGrain > PMPOffBits
12}
13
14abstract class PMPBundle(implicit val p: Parameters) extends Bundle with PMPConst
15abstract class PMPModule(implicit val p: Parameters) extends Module with PMPConst
16
17class PMPEntryHandleModule(implicit p: Parameters) extends PMPModule {
18  val io = IO(new PMPEntryHandleIOBundle)
19
20  val pmpCfg   = io.in.pmpCfg
21  val pmpAddr  = io.in.pmpAddr
22
23  val ren   = io.in.ren
24  val wen   = io.in.wen
25  val addr  = io.in.addr
26  val waddr = io.in.waddr
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 && (waddr === (0x3A0 + 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 && (waddr === (0x3B0 + 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 === (0x3B0 + 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 waddr = UInt(12.W)
96    val wdata = UInt(64.W)
97    val pmpCfg  = Vec(NumPMP, new PMPCfgBundle)
98    val pmpAddr = Vec(NumPMP, new PMPAddrBundle)
99  })
100
101  val out = Output(new Bundle {
102    val pmpCfgWData  = UInt(PMXLEN.W)
103    val pmpAddrRData = Vec(NumPMP, UInt(64.W))
104    val pmpAddrWData = Vec(NumPMP, UInt(64.W))
105  })
106}
107
108trait PMPReadWrite extends PMPConst {
109  def matchMask(cfg: PMPCfgBundle, paddr: UInt): UInt = {
110    val matchMaskCAddr = Cat(paddr, cfg.A.asUInt(0)) | (((1 << PlatformGrain) - 1) >> PMPOffBits).U((paddr.getWidth + 1).W)
111    Cat(matchMaskCAddr & (~(matchMaskCAddr + 1.U)).asUInt, ((1 << PMPOffBits) - 1).U(PMPOffBits.W))
112  }
113
114  /**
115   * In general, the PMP grain is 2**{G+2} bytes. when G >= 1, na4 is not selectable.
116   * When G >= 2 and cfg.A(1) is set(then the mode is napot), the bits addr(G-2, 0) read as zeros.
117   * When G >= 1 and cfg.A(1) is clear(the mode is off or tor), the addr(G-1, 0) read as zeros.
118   * The low Offbits is dropped
119   * @param cfg
120   * @param addr
121   * @return
122   */
123  def readAddr(cfg: PMPCfgBundle, addr: UInt): UInt = {
124    val G = PlatformGrain - PMPOffBits
125    require(G >= 0)
126    if (G == 0) {
127      addr
128    } else if (G >= 2) {
129      Mux(PMPCfgAField.isNa4OrNapot(cfg), setLowBits(addr, G-1), clearLowBits(addr, G))
130    } else { // G is 1
131      Mux(PMPCfgAField.isOffOrTor(cfg), clearLowBits(addr, G), addr)
132    }
133  }
134
135  def setLowBits(data: UInt, num: Int): UInt = {
136    require(num >= 0)
137    data | ((1 << num)-1).U
138  }
139
140  /**
141   * mask the data's low num bits (lsb)
142   * @param data
143   * @param num
144   * @return
145   */
146  def clearLowBits(data: UInt, num: Int): UInt = {
147    require(num >= 0)
148    // use Cat instead of & with mask to avoid "Signal Width" problem
149    if (num == 0) {
150      data
151    } else {
152      Cat(data(data.getWidth - 1, num), 0.U(num.W))
153    }
154  }
155
156}
157
158/**
159 * PMPEntry for outside pmp copies with one more elements mask to help napot match
160 * TODO: make mask an element, not an method, for timing opt
161 */
162class PMPEntry(implicit p: Parameters) extends PMPBundle with PMPReadWrite {
163  val cfg  = new PMPCfgBundle
164  val addr = new PMPAddrBundle
165  val mask = UInt(PMPAddrBits.W) // help to match in napot
166
167  def gen(cfg: PMPCfgBundle, addr: PMPAddrBundle, mask: UInt) = {
168    require(addr.ADDRESS.getWidth == this.addr.ADDRESS.getWidth)
169    this.cfg := cfg
170    this.addr.ADDRESS := addr.ADDRESS
171    this.mask := mask
172  }
173
174  // generate match mask to help match in napot mode
175  def matchMask(paddr: UInt): UInt = {
176    matchMask(cfg, paddr)
177  }
178}