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