-
Notifications
You must be signed in to change notification settings - Fork 572
/
Arbiter.scala
155 lines (131 loc) · 4.63 KB
/
Arbiter.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
// SPDX-License-Identifier: Apache-2.0
/** Arbiters in all shapes and sizes.
*/
package chisel3.util
import chisel3._
/** IO bundle definition for an Arbiter, which takes some number of ready-valid inputs and outputs
* (selects) at most one.
* @groupdesc Signals The actual hardware fields of the Bundle
*
* @param gen data type
* @param n number of inputs
*/
class ArbiterIO[T <: Data](private val gen: T, val n: Int) extends Bundle {
// See github.com/freechipsproject/chisel3/issues/765 for why gen is a private val and proposed replacement APIs.
/** Input data, one per potential sender
*
* @group Signals
*/
val in = Flipped(Vec(n, Decoupled(gen)))
/** Output data after arbitration
*
* @group Signals
*/
val out = Decoupled(gen)
/** Index indicating which sender was chosen as output
*
* @group Signals
*/
val chosen = Output(UInt(log2Ceil(n).W))
}
/** Arbiter Control determining which producer has access
*/
private object ArbiterCtrl {
def apply(request: Seq[Bool]): Seq[Bool] = request.length match {
case 0 => Seq()
case 1 => Seq(true.B)
case _ => true.B +: request.tail.init.scanLeft(request.head)(_ || _).map(!_)
}
}
abstract class LockingArbiterLike[T <: Data](gen: T, n: Int, count: Int, needsLock: Option[T => Bool]) extends Module {
def grant: Seq[Bool]
def choice: UInt
val io = IO(new ArbiterIO(gen, n))
io.chosen := choice
io.out.valid := io.in(io.chosen).valid
io.out.bits := io.in(io.chosen).bits
if (count > 1) {
val lockCount = Counter(count)
val lockIdx = Reg(UInt())
val locked = lockCount.value =/= 0.U
val wantsLock = needsLock.map(_(io.out.bits)).getOrElse(true.B)
when(io.out.fire && wantsLock) {
lockIdx := io.chosen
lockCount.inc()
}
when(locked) { io.chosen := lockIdx }
for ((in, (g, i)) <- io.in.zip(grant.zipWithIndex))
in.ready := Mux(locked, lockIdx === i.asUInt, g) && io.out.ready
} else {
for ((in, g) <- io.in.zip(grant))
in.ready := g && io.out.ready
}
}
class LockingRRArbiter[T <: Data](gen: T, n: Int, count: Int, needsLock: Option[T => Bool] = None)
extends LockingArbiterLike[T](gen, n, count, needsLock) {
// this register is not initialized on purpose, see #267
lazy val lastGrant = RegEnable(io.chosen, io.out.fire)
lazy val grantMask = (0 until n).map(_.asUInt > lastGrant)
lazy val validMask = io.in.zip(grantMask).map { case (in, g) => in.valid && g }
override def grant: Seq[Bool] = {
val ctrl = ArbiterCtrl((0 until n).map(i => validMask(i)) ++ io.in.map(_.valid))
(0 until n).map(i => ctrl(i) && grantMask(i) || ctrl(i + n))
}
override lazy val choice = WireDefault((n - 1).asUInt)
for (i <- n - 2 to 0 by -1)
when(io.in(i).valid) { choice := i.asUInt }
for (i <- n - 1 to 1 by -1)
when(validMask(i)) { choice := i.asUInt }
}
class LockingArbiter[T <: Data](gen: T, n: Int, count: Int, needsLock: Option[T => Bool] = None)
extends LockingArbiterLike[T](gen, n, count, needsLock) {
def grant: Seq[Bool] = ArbiterCtrl(io.in.map(_.valid))
override lazy val choice = WireDefault((n - 1).asUInt)
for (i <- n - 2 to 0 by -1)
when(io.in(i).valid) { choice := i.asUInt }
}
/** Hardware module that is used to sequence n producers into 1 consumer.
* Producers are chosen in round robin order.
*
* @param gen data type
* @param n number of inputs
* @example {{{
* val arb = Module(new RRArbiter(UInt(), 2))
* arb.io.in(0) <> producer0.io.out
* arb.io.in(1) <> producer1.io.out
* consumer.io.in <> arb.io.out
* }}}
*/
class RRArbiter[T <: Data](val gen: T, val n: Int) extends LockingRRArbiter[T](gen, n, 1)
/** Hardware module that is used to sequence n producers into 1 consumer.
* Priority is given to lower producer.
*
* @param gen data type
* @param n number of inputs
*
* @example {{{
* val arb = Module(new Arbiter(UInt(), 2))
* arb.io.in(0) <> producer0.io.out
* arb.io.in(1) <> producer1.io.out
* consumer.io.in <> arb.io.out
* }}}
*/
class Arbiter[T <: Data](val gen: T, val n: Int) extends Module {
/** Give this Arbiter a default, stable desired name using the supplied `Data`
* generator's `typeName` and input count parameter
*/
override def desiredName = s"Arbiter${n}_${gen.typeName}"
val io = IO(new ArbiterIO(gen, n))
io.chosen := (n - 1).asUInt
io.out.bits := io.in(n - 1).bits
for (i <- n - 2 to 0 by -1) {
when(io.in(i).valid) {
io.chosen := i.asUInt
io.out.bits := io.in(i).bits
}
}
val grant = ArbiterCtrl(io.in.map(_.valid))
for ((in, g) <- io.in.zip(grant))
in.ready := g && io.out.ready
io.out.valid := !grant.last || io.in.last.valid
}