xref: /XiangShan/src/main/scala/device/AXI4Plic.scala (revision 2225d46ebbe2fd16b9b29963c27a7d0385a42709)
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(val numCores: Int, val numExtIntrs: Int) extends Bundle{
76  val intrVec = Input(UInt(numExtIntrs.W))
77  val meip = Output(Vec(numCores, Bool()))
78}
79
80class AXI4Plic
81(
82  address: Seq[AddressSet],
83  numCores: Int,
84  numExtIntrs: Int,
85  sim: Boolean = false
86)(implicit p: Parameters)
87  extends AXI4SlaveModule(address, executable = false, _extra = new PlicIO(numCores, numExtIntrs))
88{
89  override lazy val module = new AXI4SlaveModuleImp[PlicIO](this) {
90    require(numCores <= PLICConsts.maxDevices)
91    require(numExtIntrs <= PLICConsts.maxHarts)
92    val addressSpaceSize = 0x4000000
93    val addressBits = log2Up(addressSpaceSize)
94
95    def getOffset(addr: UInt) = addr(addressBits - 1, 0)
96
97    val priority = List.fill(numExtIntrs)(Reg(UInt(32.W)))
98    val priorityMap = priority.zipWithIndex.map { case (r, intr) => RegMap((intr + 1) * 4, r) }.toMap
99
100    val nrIntrWord = (numExtIntrs + 31) / 32 // roundup
101    // pending bits are updated in the unit of bit by PLIC,
102    // so define it as vectors of bits, instead of UInt(32.W)
103    val pending = List.fill(nrIntrWord)(RegInit(0.U.asTypeOf(Vec(32, Bool()))))
104    val pendingMap = pending.zipWithIndex.map { case (r, intrWord) =>
105      RegMap(0x1000 + intrWord * 4, Cat(r.reverse), RegMap.Unwritable)
106    }.toMap
107
108    val enable = List.fill(numCores)(List.fill(nrIntrWord)(RegInit(0.U(32.W))))
109    val enableMap = enable.zipWithIndex.map { case (l, hart) =>
110      l.zipWithIndex.map { case (r, intrWord) => RegMap(0x2000 + hart * 0x80 + intrWord * 4, r) }
111    }.reduce(_ ++ _).toMap
112
113    val threshold = List.fill(numCores)(Reg(UInt(32.W)))
114    val thresholdMap = threshold.zipWithIndex.map {
115      case (r, hart) => RegMap(0x200000 + hart * 0x1000, r)
116    }.toMap
117
118    val inHandle = RegInit(0.U.asTypeOf(Vec(numExtIntrs + 1, Bool())))
119
120    def completionFn(wdata: UInt) = {
121      inHandle(wdata(31, 0)) := false.B
122      0.U
123    }
124
125    val claimCompletion = List.fill(numCores)(Reg(UInt(32.W)))
126    val claimCompletionMap = claimCompletion.zipWithIndex.map {
127      case (r, hart) => {
128        val addr = 0x200004 + hart * 0x1000
129        when(in.r.fire() && (getOffset(raddr) === addr.U)) {
130          inHandle(r) := true.B
131        }
132        RegMap(addr, r, completionFn)
133      }
134    }.toMap
135
136    val intrVecReg = Wire(UInt(numExtIntrs.W))
137    intrVecReg := RegNext(RegNext(RegNext(io.extra.get.intrVec)))
138    intrVecReg.asBools.zipWithIndex.map { case (intr, i) => {
139      val id = i + 1
140      when(intr) {
141        pending(id / 32)(id % 32) := true.B
142      }
143      when(inHandle(id)) {
144        pending(id / 32)(id % 32) := false.B
145      }
146    }
147    }
148
149    val pendingVec = Cat(pending.map(x => Cat(x.reverse)))
150    claimCompletion.zipWithIndex.map { case (r, hart) => {
151      val takenVec = pendingVec & Cat(enable(hart))
152      r := Mux(takenVec === 0.U, 0.U, PriorityEncoder(takenVec))
153    }
154    }
155
156    val mapping = priorityMap ++ pendingMap ++ enableMap ++ thresholdMap ++ claimCompletionMap
157
158    val rdata = Wire(UInt(32.W))
159    RegMap.generate(mapping, getOffset(raddr), rdata,
160      getOffset(waddr), in.w.fire(), in.w.bits.data, MaskExpand(in.w.bits.strb >> waddr(2, 0)))
161    // narrow read
162    in.r.bits.data := Fill(2, rdata)
163
164    io.extra.get.meip.zipWithIndex.map { case (ip, hart) => ip := claimCompletion(hart) =/= 0.U }
165  }
166}
167