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
|
// See LICENSE for license details.
/** Arbiters in all shapes and sizes.
*/
package chisel3.util
import chisel3._
import chisel3.internal.naming.chiselName // can't use chisel3_ version because of compile order
/** IO bundle definition for an Arbiter, which takes some number of ready-valid inputs and outputs
* (selects) at most one.
*
* @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.
val in = Flipped(Vec(n, Decoupled(gen)))
val out = Decoupled(gen)
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 {
protected def grant: Seq[Bool]
protected 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) {
private lazy val lastGrant = RegEnable(io.chosen, io.out.fire())
private lazy val grantMask = (0 until n).map(_.asUInt > lastGrant)
private lazy val validMask = io.in zip grantMask map { case (in, g) => in.valid && g }
override protected 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 protected 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) {
protected def grant: Seq[Bool] = ArbiterCtrl(io.in.map(_.valid))
override protected 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
* }}}
*/
@chiselName
class RRArbiter[T <: Data](gen:T, 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
* }}}
*/
@chiselName
class Arbiter[T <: Data](gen: T, n: Int) extends Module {
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
}
}
private 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
}
|