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}