-
Notifications
You must be signed in to change notification settings - Fork 50
/
Copy pathGCDSpec.scala
168 lines (137 loc) · 4.62 KB
/
GCDSpec.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
156
157
158
159
160
161
162
163
164
165
166
167
// SPDX-License-Identifier: Apache-2.0
package examples
import java.io.File
import chisel3._
import chisel3.util._
import chisel3.iotesters._
import treadle.chronometry.Timer
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
object RealGCD2 {
val num_width = 16
}
class RealGCD2Input extends Bundle {
private val theWidth = RealGCD2.num_width
val a = UInt(theWidth.W)
val b = UInt(theWidth.W)
}
class RealGCD2 extends Module {
private val theWidth = RealGCD2.num_width
val io = IO(new Bundle {
// we use quirky names here to test fixed bug in verilator backend
val RealGCD2in = Flipped(Decoupled(new RealGCD2Input()))
val RealGCD2out = Valid(UInt(theWidth.W))
})
val x = Reg(UInt(theWidth.W))
val y = Reg(UInt(theWidth.W))
val p = RegInit(false.B)
val ti = RegInit(0.U(theWidth.W))
ti := ti + 1.U
io.RealGCD2in.ready := !p
when (io.RealGCD2in.valid && !p) {
x := io.RealGCD2in.bits.a
y := io.RealGCD2in.bits.b
p := true.B
}
when (p) {
when (x > y) { x := y; y := x }
.otherwise { y := y - x }
}
io.RealGCD2out.bits := x
io.RealGCD2out.valid := y === 0.U && p
when (io.RealGCD2out.valid) {
p := false.B
}
}
class GCDPeekPokeTester(c: RealGCD2, maxX: Int = 10, maxY: Int = 10, showTiming: Boolean = false)
extends PeekPokeTester(c) {
val timer = new Timer
timer("overall") {
for {
i <- 1 to maxX
j <- 1 to maxY
} {
val (gcd_value, _) = GCDCalculator.computeGcdResultsAndCycles(i, j)
timer("operation") {
poke(c.io.RealGCD2in.bits.a, i)
poke(c.io.RealGCD2in.bits.b, j)
poke(c.io.RealGCD2in.valid, 1)
var count = 0
while (peek(c.io.RealGCD2out.valid) == BigInt(0) && count < 20000) {
step(1)
count += 1
}
if (count > 30000) {
// println(s"Waited $count cycles on gcd inputs $i, $j, giving up")
System.exit(0)
}
expect(c.io.RealGCD2out.bits, gcd_value)
step(1)
}
}
}
if(showTiming) {
println(s"\n${timer.report()}")
}
}
class GCDSpec extends AnyFlatSpec with Matchers {
behavior of "GCDSpec"
it should "compute gcd excellently" in {
iotesters.Driver.execute(() => new RealGCD2, new TesterOptionsManager) { c =>
new GCDPeekPokeTester(c)
} should be(true)
}
it should "run verilator via command line arguments" in {
// val args = Array.empty[String]
val args = Array("--backend-name", "verilator")
iotesters.Driver.execute(args, () => new RealGCD2) { c =>
new GCDPeekPokeTester(c)
} should be (true)
}
it should "run firrtl-interpreter via command line arguments" in {
// val args = Array.empty[String]
val args = Array("--backend-name", "firrtl", "--fint-write-vcd")
iotesters.Driver.execute(args, () => new RealGCD2) { c =>
new GCDPeekPokeTester(c)
} should be (true)
}
it should "run firrtl via direct options configuration" in {
val manager = new TesterOptionsManager {
testerOptions = testerOptions.copy(backendName = "firrtl", testerSeed = 7L)
interpreterOptions = interpreterOptions.copy(setVerbose = false, writeVCD = true)
}
iotesters.Driver.execute(() => new RealGCD2, manager) { c =>
new GCDPeekPokeTester(c)
} should be (true)
}
"using verilator backend with suppress-verilator-backend" should "not create a vcd" in {
iotesters.Driver.execute(
Array("--backend-name", "verilator", "--generate-vcd-output", "off",
"--target-dir", "test_run_dir/gcd_no_vcd", "--top-name", "gcd_no_vcd"),
() => new RealGCD2
) {
c => new GCDPeekPokeTester(c)
} should be(true)
new File("test_run_dir/gcd_no_vcd/RealGCD2.vcd").exists() should be (false)
}
"using verilator default behavior" should "create a vcd" in {
iotesters.Driver.execute(
Array("--backend-name", "verilator",
"--target-dir", "test_run_dir/gcd_make_vcd", "--top-name", "gcd_make_vcd"),
() => new RealGCD2
) {
c => new GCDPeekPokeTester(c)
} should be(true)
new File("test_run_dir/gcd_make_vcd/RealGCD2.vcd").exists() should be (true)
}
it should "run verilator with larger input vector to run regressions" in {
//
// Use this test combined with changing the comments on VerilatorBackend.scala lines 153 and 155 to
// measure the consequence of that change, at the time of last using this the cost appeared to be < 3%
//
val args = Array("--backend-name", "verilator")
iotesters.Driver.execute(args, () => new RealGCD2) { c =>
new GCDPeekPokeTester(c, 100, 1000, showTiming = true)
} should be (true)
}
}