1/*************************************************************************************** 2* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences 3* Copyright (c) 2020-2021 Peng Cheng Laboratory 4* 5* XiangShan is licensed under Mulan PSL v2. 6* You can use this software according to the terms and conditions of the Mulan PSL v2. 7* You may obtain a copy of Mulan PSL v2 at: 8* http://license.coscl.org.cn/MulanPSL2 9* 10* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 11* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 12* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 13* 14* See the Mulan PSL v2 for more details. 15***************************************************************************************/ 16 17package device 18 19import chisel3._ 20import chisel3.util._ 21import org.chipsalliance.cde.config._ 22import freechips.rocketchip.diplomacy._ 23import utils.HasTLDump 24import utility.{RegMap, MaskExpand, XSDebug} 25 26/* base + 0x000000: Reserved (interrupt source 0 does not exist) 27 base + 0x000004: Interrupt source 1 priority 28 base + 0x000008: Interrupt source 2 priority 29 ... 30 base + 0x000FFC: Interrupt source 1023 priority 31 base + 0x001000: Interrupt Pending bit 0-31 32 base + 0x00107C: Interrupt Pending bit 992-1023 33 ... 34 base + 0x002000: Enable bits for sources 0-31 on context 0 35 base + 0x002004: Enable bits for sources 32-63 on context 0 36 ... 37 base + 0x00207F: Enable bits for sources 992-1023 on context 0 38 base + 0x002080: Enable bits for sources 0-31 on context 1 39 base + 0x002084: Enable bits for sources 32-63 on context 1 40 ... 41 base + 0x0020FF: Enable bits for sources 992-1023 on context 1 42 base + 0x002100: Enable bits for sources 0-31 on context 2 43 base + 0x002104: Enable bits for sources 32-63 on context 2 44 ... 45 base + 0x00217F: Enable bits for sources 992-1023 on context 2 46 ... 47 base + 0x1F1F80: Enable bits for sources 0-31 on context 15871 48 base + 0x1F1F84: Enable bits for sources 32-63 on context 15871 49 base + 0x1F1FFF: Enable bits for sources 992-1023 on context 15871 50 ... 51 base + 0x1FFFFC: Reserved 52 base + 0x200000: Priority threshold for context 0 53 base + 0x200004: Claim/complete for context 0 54 base + 0x200008: Reserved 55 ... 56 base + 0x200FFC: Reserved 57 base + 0x201000: Priority threshold for context 1 58 base + 0x201004: Claim/complete for context 1 59 ... 60 base + 0x3FFE000: Priority threshold for context 15871 61 base + 0x3FFE004: Claim/complete for context 15871 62 base + 0x3FFE008: Reserved 63 ... 64 base + 0x3FFFFFC: Reserved */ 65 66object PLICConsts 67{ 68 def maxDevices = 1023 69 def maxHarts = 15872 70 def priorityBase = 0x0 71 def pendingBase = 0x1000 72 def enableBase = 0x2000 73 def hartBase = 0x200000 74 75 def claimOffset = 4 76 def priorityBytes = 4 77 78 def enableOffset(i: Int) = i * ((maxDevices+7)/8) 79 def hartOffset(i: Int) = i * 0x1000 80 def enableBase(i: Int):Int = enableOffset(i) + enableBase 81 def hartBase(i: Int):Int = hartOffset(i) + hartBase 82 83 def size(maxHarts: Int): Int = { 84 require(maxHarts > 0 && maxHarts <= maxHarts, s"Must be: maxHarts=$maxHarts > 0 && maxHarts <= PLICConsts.maxHarts=${PLICConsts.maxHarts}") 85 1 << log2Ceil(hartBase(maxHarts)) 86 } 87 88 require(hartBase >= enableBase(maxHarts)) 89} 90 91class PlicIO(val numCores: Int, val numExtIntrs: Int) extends Bundle{ 92 val intrVec = Input(UInt(numExtIntrs.W)) 93 val meip = Output(Vec(numCores, Bool())) 94} 95 96class AXI4Plic 97( 98 address: Seq[AddressSet], 99 numCores: Int, 100 numExtIntrs: Int, 101 sim: Boolean = false 102)(implicit p: Parameters) 103 extends AXI4SlaveModule(address, executable = false, _extra = new PlicIO(numCores, numExtIntrs)) 104{ 105 override lazy val module = new AXI4SlaveModuleImp[PlicIO](this) { 106 require(numCores <= PLICConsts.maxDevices) 107 require(numExtIntrs <= PLICConsts.maxHarts) 108 val addressSpaceSize = 0x4000000 109 val addressBits = log2Up(addressSpaceSize) 110 111 def getOffset(addr: UInt) = addr(addressBits - 1, 0) 112 113 val priority = List.fill(numExtIntrs)(Reg(UInt(32.W))) 114 val priorityMap = priority.zipWithIndex.map { case (r, intr) => RegMap((intr + 1) * 4, r) }.toMap 115 116 val nrIntrWord = (numExtIntrs + 31) / 32 // roundup 117 // pending bits are updated in the unit of bit by PLIC, 118 // so define it as vectors of bits, instead of UInt(32.W) 119 val pending = List.fill(nrIntrWord)(RegInit(0.U.asTypeOf(Vec(32, Bool())))) 120 val pendingMap = pending.zipWithIndex.map { case (r, intrWord) => 121 RegMap(0x1000 + intrWord * 4, Cat(r.reverse), RegMap.Unwritable) 122 }.toMap 123 124 val enable = List.fill(numCores)(List.fill(nrIntrWord)(RegInit(0.U(32.W)))) 125 val enableMap = enable.zipWithIndex.map { case (l, hart) => 126 l.zipWithIndex.map { case (r, intrWord) => RegMap(0x2000 + hart * 0x80 + intrWord * 4, r) } 127 }.reduce(_ ++ _).toMap 128 129 val threshold = List.fill(numCores)(Reg(UInt(32.W))) 130 val thresholdMap = threshold.zipWithIndex.map { 131 case (r, hart) => RegMap(0x200000 + hart * 0x1000, r) 132 }.toMap 133 134 val inHandle = RegInit(0.U.asTypeOf(Vec(numExtIntrs + 1, Bool()))) 135 136 def completionFn(wdata: UInt) = { 137 inHandle(wdata(31, 0)) := false.B 138 0.U 139 } 140 141 val claimCompletion = List.fill(numCores)(Reg(UInt(32.W))) 142 val claimCompletionMap = claimCompletion.zipWithIndex.map { 143 case (r, hart) => { 144 val addr = 0x200004 + hart * 0x1000 145 when(in.r.fire && (getOffset(raddr) === addr.U)) { 146 inHandle(r) := true.B 147 } 148 RegMap(addr, r, completionFn) 149 } 150 }.toMap 151 152 val intrVecReg = Wire(UInt(numExtIntrs.W)) 153 intrVecReg := RegNext(RegNext(RegNext(io.extra.get.intrVec))) 154 intrVecReg.asBools.zipWithIndex.map { case (intr, i) => { 155 val id = i + 1 156 when(intr) { 157 pending(id / 32)(id % 32) := true.B 158 } 159 when(inHandle(id)) { 160 pending(id / 32)(id % 32) := false.B 161 } 162 } 163 } 164 165 val pendingVec = Cat(pending.map(x => Cat(x.reverse))) 166 claimCompletion.zipWithIndex.map { case (r, hart) => { 167 val takenVec = pendingVec & Cat(enable(hart)) 168 r := Mux(takenVec === 0.U, 0.U, PriorityEncoder(takenVec)) 169 } 170 } 171 172 val mapping = priorityMap ++ pendingMap ++ enableMap ++ thresholdMap ++ claimCompletionMap 173 174 val rdata = Wire(UInt(32.W)) 175 RegMap.generate(mapping, getOffset(raddr), rdata, 176 getOffset(waddr), in.w.fire, in.w.bits.data, MaskExpand(in.w.bits.strb >> waddr(2, 0))) 177 // narrow read 178 in.r.bits.data := Fill(2, rdata) 179 180 io.extra.get.meip.zipWithIndex.map { case (ip, hart) => ip := claimCompletion(hart) =/= 0.U } 181 } 182} 183