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}