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