blob: 3f07810681d5fcbdc21b4c5d14af942b54cc7c8c (
plain)
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
|
// SPDX-License-Identifier: Apache-2.0
package chiselTests
import chisel3._
import chisel3.util._
import chisel3.testers.BasicTester
class Arbiter[T <: Data: Manifest](n: Int, private val gen: T) extends Module {
val io = IO(new Bundle {
val in = Flipped(Vec(n, new DecoupledIO(gen)))
val out = new DecoupledIO(gen)
})
def arbitrateTwo(a: DecoupledIO[T], b: DecoupledIO[T]) = {
val idleA :: idleB :: hasA :: hasB :: Nil = Enum(4)
val regData = Reg(gen)
val regState = RegInit(idleA)
val out = Wire(new DecoupledIO(gen))
a.ready := regState === idleA
b.ready := regState === idleB
out.valid := (regState === hasA || regState === hasB)
switch(regState) {
is(idleA) {
when(a.valid) {
regData := a.bits
regState := hasA
}.otherwise {
regState := idleB
}
}
is(idleB) {
when(b.valid) {
regData := b.bits
regState := hasB
}.otherwise {
regState := idleA
}
}
is(hasA) {
when(out.ready) {
regState := idleB
}
}
is(hasB) {
when(out.ready) {
regState := idleA
}
}
}
out.bits := regData.asUInt + 1.U
out
}
io.out <> io.in.reduceTree(arbitrateTwo)
}
class ReduceTreeBalancedTester(nodes: Int) extends BasicTester {
val cnt = RegInit(0.U(8.W))
val min = RegInit(99.U(8.W))
val max = RegInit(0.U(8.W))
val dut = Module(new Arbiter(nodes, UInt(16.W)))
for (i <- 0 until nodes) {
dut.io.in(i).valid := true.B
dut.io.in(i).bits := 0.U
}
dut.io.out.ready := true.B
when(dut.io.out.valid) {
val hops = dut.io.out.bits
when(hops < min) {
min := hops
}
when(hops > max) {
max := hops
}
}
when(!(max === 0.U || min === 99.U)) {
assert(max - min <= 1.U)
}
cnt := cnt + 1.U
when(cnt === 10.U) {
stop()
}
}
class ReduceTreeBalancedSpec extends ChiselPropSpec {
property("Tree shall be fair and shall have a maximum difference of one hop for each node") {
// This test will fail for 5 nodes due to an unbalanced tree.
// A fix is on the way.
for (n <- 1 to 5) {
assertTesterPasses {
new ReduceTreeBalancedTester(n)
}
}
}
}
|