1package device 2 3import chisel3._ 4import chisel3.util._ 5import chipsalliance.rocketchip.config._ 6import freechips.rocketchip.diplomacy._ 7import utils.MaskExpand 8import utils.{HasTLDump, XSDebug, RegMap} 9 10/* base + 0x000000: Reserved (interrupt source 0 does not exist) 11 base + 0x000004: Interrupt source 1 priority 12 base + 0x000008: Interrupt source 2 priority 13 ... 14 base + 0x000FFC: Interrupt source 1023 priority 15 base + 0x001000: Interrupt Pending bit 0-31 16 base + 0x00107C: Interrupt Pending bit 992-1023 17 ... 18 base + 0x002000: Enable bits for sources 0-31 on context 0 19 base + 0x002004: Enable bits for sources 32-63 on context 0 20 ... 21 base + 0x00207F: Enable bits for sources 992-1023 on context 0 22 base + 0x002080: Enable bits for sources 0-31 on context 1 23 base + 0x002084: Enable bits for sources 32-63 on context 1 24 ... 25 base + 0x0020FF: Enable bits for sources 992-1023 on context 1 26 base + 0x002100: Enable bits for sources 0-31 on context 2 27 base + 0x002104: Enable bits for sources 32-63 on context 2 28 ... 29 base + 0x00217F: Enable bits for sources 992-1023 on context 2 30 ... 31 base + 0x1F1F80: Enable bits for sources 0-31 on context 15871 32 base + 0x1F1F84: Enable bits for sources 32-63 on context 15871 33 base + 0x1F1FFF: Enable bits for sources 992-1023 on context 15871 34 ... 35 base + 0x1FFFFC: Reserved 36 base + 0x200000: Priority threshold for context 0 37 base + 0x200004: Claim/complete for context 0 38 base + 0x200008: Reserved 39 ... 40 base + 0x200FFC: Reserved 41 base + 0x201000: Priority threshold for context 1 42 base + 0x201004: Claim/complete for context 1 43 ... 44 base + 0x3FFE000: Priority threshold for context 15871 45 base + 0x3FFE004: Claim/complete for context 15871 46 base + 0x3FFE008: Reserved 47 ... 48 base + 0x3FFFFFC: Reserved */ 49 50object PLICConsts 51{ 52 def maxDevices = 1023 53 def maxHarts = 15872 54 def priorityBase = 0x0 55 def pendingBase = 0x1000 56 def enableBase = 0x2000 57 def hartBase = 0x200000 58 59 def claimOffset = 4 60 def priorityBytes = 4 61 62 def enableOffset(i: Int) = i * ((maxDevices+7)/8) 63 def hartOffset(i: Int) = i * 0x1000 64 def enableBase(i: Int):Int = enableOffset(i) + enableBase 65 def hartBase(i: Int):Int = hartOffset(i) + hartBase 66 67 def size(maxHarts: Int): Int = { 68 require(maxHarts > 0 && maxHarts <= maxHarts, s"Must be: maxHarts=$maxHarts > 0 && maxHarts <= PLICConsts.maxHarts=${PLICConsts.maxHarts}") 69 1 << log2Ceil(hartBase(maxHarts)) 70 } 71 72 require(hartBase >= enableBase(maxHarts)) 73} 74 75class PlicIO extends Bundle with xiangshan.HasXSParameter { 76 val intrVec = Input(UInt(NrExtIntr.W)) 77 val meip = Output(Vec(top.Parameters.get.socParameters.NumCores, Bool())) 78} 79 80class AXI4Plic 81( 82 address: Seq[AddressSet], 83 sim: Boolean = false 84)(implicit p: Parameters) 85 extends AXI4SlaveModule(address, executable = false, _extra = new PlicIO) with xiangshan.HasXSParameter 86{ 87 override lazy val module = new AXI4SlaveModuleImp[PlicIO](this) { 88 val NumCores = top.Parameters.get.socParameters.NumCores 89 require(NrExtIntr <= PLICConsts.maxDevices) 90 require(NumCores <= PLICConsts.maxHarts) 91 val addressSpaceSize = 0x4000000 92 val addressBits = log2Up(addressSpaceSize) 93 94 def getOffset(addr: UInt) = addr(addressBits - 1, 0) 95 96 val priority = List.fill(NrExtIntr)(Reg(UInt(32.W))) 97 val priorityMap = priority.zipWithIndex.map { case (r, intr) => RegMap((intr + 1) * 4, r) }.toMap 98 99 val nrIntrWord = (NrExtIntr + 31) / 32 // roundup 100 // pending bits are updated in the unit of bit by PLIC, 101 // so define it as vectors of bits, instead of UInt(32.W) 102 val pending = List.fill(nrIntrWord)(RegInit(0.U.asTypeOf(Vec(32, Bool())))) 103 val pendingMap = pending.zipWithIndex.map { case (r, intrWord) => 104 RegMap(0x1000 + intrWord * 4, Cat(r.reverse), RegMap.Unwritable) 105 }.toMap 106 107 val enable = List.fill(NumCores)(List.fill(nrIntrWord)(RegInit(0.U(32.W)))) 108 val enableMap = enable.zipWithIndex.map { case (l, hart) => 109 l.zipWithIndex.map { case (r, intrWord) => RegMap(0x2000 + hart * 0x80 + intrWord * 4, r) } 110 }.reduce(_ ++ _).toMap 111 112 val threshold = List.fill(NumCores)(Reg(UInt(32.W))) 113 val thresholdMap = threshold.zipWithIndex.map { 114 case (r, hart) => RegMap(0x200000 + hart * 0x1000, r) 115 }.toMap 116 117 val inHandle = RegInit(0.U.asTypeOf(Vec(NrExtIntr + 1, Bool()))) 118 119 def completionFn(wdata: UInt) = { 120 inHandle(wdata(31, 0)) := false.B 121 0.U 122 } 123 124 val claimCompletion = List.fill(NumCores)(Reg(UInt(32.W))) 125 val claimCompletionMap = claimCompletion.zipWithIndex.map { 126 case (r, hart) => { 127 val addr = 0x200004 + hart * 0x1000 128 when(in.r.fire() && (getOffset(raddr) === addr.U)) { 129 inHandle(r) := true.B 130 } 131 RegMap(addr, r, completionFn) 132 } 133 }.toMap 134 135 io.extra.get.intrVec.asBools.zipWithIndex.map { case (intr, i) => { 136 val id = i + 1 137 when(intr) { 138 pending(id / 32)(id % 32) := true.B 139 } 140 when(inHandle(id)) { 141 pending(id / 32)(id % 32) := false.B 142 } 143 } 144 } 145 146 val pendingVec = Cat(pending.map(x => Cat(x.reverse))) 147 claimCompletion.zipWithIndex.map { case (r, hart) => { 148 val takenVec = pendingVec & Cat(enable(hart)) 149 r := Mux(takenVec === 0.U, 0.U, PriorityEncoder(takenVec)) 150 } 151 } 152 153 val mapping = priorityMap ++ pendingMap ++ enableMap ++ thresholdMap ++ claimCompletionMap 154 155 val rdata = Wire(UInt(32.W)) 156 RegMap.generate(mapping, getOffset(raddr), rdata, 157 getOffset(waddr), in.w.fire(), in.w.bits.data, MaskExpand(in.w.bits.strb >> waddr(2, 0))) 158 // narrow read 159 in.r.bits.data := Fill(2, rdata) 160 161 io.extra.get.meip.zipWithIndex.map { case (ip, hart) => ip := claimCompletion(hart) =/= 0.U } 162 } 163} 164