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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
|
// SPDX-License-Identifier: Apache-2.0
package chiselTests
import chisel3._
import chisel3.experimental._
import chisel3.stage.ChiselStage
import chisel3.testers.{BasicTester, TesterDriver}
import chisel3.util._
class BlackBoxInverter extends BlackBox {
val io = IO(new Bundle() {
val in = Input(Bool())
val out = Output(Bool())
})
}
// Due to the removal of "val io", this technically works
// This style is discouraged, please use "val io"
class BlackBoxInverterSuggestName extends BlackBox {
override def desiredName: String = "BlackBoxInverter"
val foo = IO(new Bundle() {
val in = Input(Bool())
val out = Output(Bool())
}).suggestName("io")
}
class BlackBoxPassthrough extends BlackBox {
val io = IO(new Bundle() {
val in = Input(Bool())
val out = Output(Bool())
})
}
// Test Flip on top-level IO
class BlackBoxPassthrough2 extends BlackBox {
val io = IO(Flipped(new Bundle() {
val in = Output(Bool())
val out = Input(Bool())
}))
}
class BlackBoxRegister extends BlackBox {
val io = IO(new Bundle() {
val clock = Input(Clock())
val in = Input(Bool())
val out = Output(Bool())
})
}
class BlackBoxTester extends BasicTester {
val blackBoxPos = Module(new BlackBoxInverter)
val blackBoxNeg = Module(new BlackBoxInverter)
blackBoxPos.io.in := 1.U
blackBoxNeg.io.in := 0.U
assert(blackBoxNeg.io.out === 1.U)
assert(blackBoxPos.io.out === 0.U)
stop()
}
class BlackBoxTesterSuggestName extends BasicTester {
val blackBoxPos = Module(new BlackBoxInverterSuggestName)
val blackBoxNeg = Module(new BlackBoxInverterSuggestName)
blackBoxPos.foo.in := 1.U
blackBoxNeg.foo.in := 0.U
assert(blackBoxNeg.foo.out === 1.U)
assert(blackBoxPos.foo.out === 0.U)
stop()
}
class BlackBoxFlipTester extends BasicTester {
val blackBox = Module(new BlackBoxPassthrough2)
blackBox.io.in := 1.U
assert(blackBox.io.out === 1.U)
stop()
}
/** Instantiate multiple BlackBoxes with similar interfaces but different
* functionality. Used to detect failures in BlackBox naming and module
* deduplication.
*/
class MultiBlackBoxTester extends BasicTester {
val blackBoxInvPos = Module(new BlackBoxInverter)
val blackBoxInvNeg = Module(new BlackBoxInverter)
val blackBoxPassPos = Module(new BlackBoxPassthrough)
val blackBoxPassNeg = Module(new BlackBoxPassthrough)
blackBoxInvPos.io.in := 1.U
blackBoxInvNeg.io.in := 0.U
blackBoxPassPos.io.in := 1.U
blackBoxPassNeg.io.in := 0.U
assert(blackBoxInvNeg.io.out === 1.U)
assert(blackBoxInvPos.io.out === 0.U)
assert(blackBoxPassNeg.io.out === 0.U)
assert(blackBoxPassPos.io.out === 1.U)
stop()
}
class BlackBoxWithClockTester extends BasicTester {
val blackBox = Module(new BlackBoxRegister)
val model = Reg(Bool())
val (cycles, end) = Counter(true.B, 15)
val impetus = cycles(0)
blackBox.io.clock := clock
blackBox.io.in := impetus
model := impetus
when(cycles > 0.U) {
assert(blackBox.io.out === model)
}
when(end) { stop() }
}
class BlackBoxConstant(value: Int) extends BlackBox(Map("VALUE" -> value, "WIDTH" -> log2Ceil(value + 1))) {
require(value >= 0, "value must be a UInt!")
val io = IO(new Bundle {
val out = Output(UInt(log2Ceil(value + 1).W))
})
}
class BlackBoxStringParam(str: String) extends BlackBox(Map("STRING" -> str)) {
val io = IO(new Bundle {
val out = UInt(32.W)
})
}
class BlackBoxRealParam(dbl: Double) extends BlackBox(Map("REAL" -> dbl)) {
val io = IO(new Bundle {
val out = UInt(64.W)
})
}
class BlackBoxTypeParam(w: Int, raw: String) extends BlackBox(Map("T" -> RawParam(raw))) {
val io = IO(new Bundle {
val out = UInt(w.W)
})
}
class BlackBoxNoIO extends BlackBox {
// Whoops! typo
val ioo = IO(new Bundle {
val out = Output(UInt(8.W))
})
}
class BlackBoxUIntIO extends BlackBox {
val io = IO(Output(UInt(8.W)))
}
class BlackBoxWithParamsTester extends BasicTester {
val blackBoxOne = Module(new BlackBoxConstant(1))
val blackBoxFour = Module(new BlackBoxConstant(4))
val blackBoxStringParamOne = Module(new BlackBoxStringParam("one"))
val blackBoxStringParamTwo = Module(new BlackBoxStringParam("two"))
val blackBoxRealParamOne = Module(new BlackBoxRealParam(1.0))
val blackBoxRealParamNeg = Module(new BlackBoxRealParam(-1.0))
val blackBoxTypeParamBit = Module(new BlackBoxTypeParam(1, "bit"))
val blackBoxTypeParamWord = Module(new BlackBoxTypeParam(32, "bit [31:0]"))
val (cycles, end) = Counter(true.B, 4)
assert(blackBoxOne.io.out === 1.U)
assert(blackBoxFour.io.out === 4.U)
assert(blackBoxStringParamOne.io.out === 1.U)
assert(blackBoxStringParamTwo.io.out === 2.U)
assert(blackBoxRealParamOne.io.out === 0x3ff0000000000000L.U)
assert(blackBoxRealParamNeg.io.out === BigInt("bff0000000000000", 16).U)
assert(blackBoxTypeParamBit.io.out === 1.U)
assert(blackBoxTypeParamWord.io.out === "hdeadbeef".U(32.W))
when(end) { stop() }
}
class BlackBoxSpec extends ChiselFlatSpec {
"A BlackBoxed inverter" should "work" in {
assertTesterPasses({ new BlackBoxTester }, Seq("/chisel3/BlackBoxTest.v"), TesterDriver.verilatorOnly)
}
"A BlackBoxed with flipped IO" should "work" in {
assertTesterPasses({ new BlackBoxFlipTester }, Seq("/chisel3/BlackBoxTest.v"), TesterDriver.verilatorOnly)
}
"Multiple BlackBoxes" should "work" in {
assertTesterPasses({ new MultiBlackBoxTester }, Seq("/chisel3/BlackBoxTest.v"), TesterDriver.verilatorOnly)
}
"A BlackBoxed register" should "work" in {
assertTesterPasses({ new BlackBoxWithClockTester }, Seq("/chisel3/BlackBoxTest.v"), TesterDriver.verilatorOnly)
}
"BlackBoxes with parameters" should "work" in {
assertTesterPasses({ new BlackBoxWithParamsTester }, Seq("/chisel3/BlackBoxTest.v"), TesterDriver.verilatorOnly)
}
"DataMirror.modulePorts" should "work with BlackBox" in {
ChiselStage.elaborate(new Module {
val io = IO(new Bundle {})
val m = Module(new BlackBoxPassthrough)
assert(DataMirror.modulePorts(m) == Seq("in" -> m.io.in, "out" -> m.io.out))
})
}
"A BlackBox using suggestName(\"io\")" should "work (but don't do this)" in {
assertTesterPasses({ new BlackBoxTesterSuggestName }, Seq("/chisel3/BlackBoxTest.v"), TesterDriver.verilatorOnly)
}
"A BlackBox with no 'val io'" should "give a reasonable error message" in {
(the[ChiselException] thrownBy {
ChiselStage.elaborate(new Module {
val inst = Module(new BlackBoxNoIO)
})
}).getMessage should include("must have a port named 'io' of type Record")
}
"A BlackBox with non-Record 'val io'" should "give a reasonable error message" in {
(the[ChiselException] thrownBy {
ChiselStage.elaborate(new Module {
val inst = Module(new BlackBoxUIntIO)
})
}).getMessage should include("must have a port named 'io' of type Record")
}
}
|