-
Notifications
You must be signed in to change notification settings - Fork 648
Expand file tree
/
Copy pathModuleChoiceSpec.scala
More file actions
193 lines (151 loc) · 6.05 KB
/
ModuleChoiceSpec.scala
File metadata and controls
193 lines (151 loc) · 6.05 KB
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
// SPDX-License-Identifier: Apache-2.0
package chiselTests
import chisel3._
import chisel3.choice.{Case, Group, ModuleChoice}
import chisel3.experimental.hierarchy.Definition
import chisel3.testing.scalatest.FileCheck
import circt.stage.ChiselStage
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
object Platform extends Group {
object FPGA extends Case
object ASIC extends Case
}
class TargetIO(width: Int) extends Bundle {
val in = Flipped(UInt(width.W))
val out = UInt(width.W)
}
class FPGATarget extends FixedIORawModule[TargetIO](new TargetIO(8)) {
io.out := io.in
}
class ASICTarget extends FixedIOExtModule[TargetIO](new TargetIO(8))
class VerifTarget extends FixedIORawModule[TargetIO](new TargetIO(8)) {
io.out := io.in
}
class ModuleWithChoice[T <: Data](
default: => FixedIOBaseModule[T]
)(alternateImpls: Seq[(Case, () => FixedIOBaseModule[T])])
extends Module {
val inst = ModuleChoice(default)(alternateImpls)
val io = IO(inst.cloneType)
io <> inst
}
class ModuleChoiceSpec extends AnyFlatSpec with Matchers with FileCheck {
it should "emit options and cases" in {
class ModuleWithValidChoices
extends ModuleWithChoice(new VerifTarget)(Seq(Platform.FPGA -> new FPGATarget, Platform.ASIC -> new ASICTarget))
info("FIRRTL emission looks good")
ChiselStage
.emitCHIRRTL(new ModuleWithValidChoices)
.fileCheck()(
"""|CHECK: option Platform :
|CHECK-NEXT: FPGA
|CHECK-NEXT: ASIC
|CHECK: instchoice inst of VerifTarget, Platform :
|CHECK-NEXT: FPGA => FPGATarget
|CHECK-NEXT: ASIC => ASICTarget""".stripMargin
)
// TODO: The Verilog ABI for Instance Choice is in flux. This test is only
// checking that things compile, not that the output matches any ABI just
// yet.
info("Verilog compilation doesn't error")
ChiselStage
.emitSystemVerilog(new ModuleWithValidChoices)
}
it should "emit options and cases for Modules including definitions" in {
class ModuleWithValidChoices
extends ModuleWithChoice(new VerifTarget)(Seq(Platform.FPGA -> new FPGATarget, Platform.ASIC -> new ASICTarget))
class TopWithDefinition extends Module {
val definitionWithChoice = Definition(new ModuleWithValidChoices)
}
ChiselStage
.emitCHIRRTL(new TopWithDefinition)
.fileCheck()(
"""|CHECK: option Platform :
|CHECK-NEXT: FPGA
|CHECK-NEXT: ASIC
|CHECK: instchoice inst of VerifTarget, Platform :
|CHECK-NEXT: FPGA => FPGATarget
|CHECK-NEXT: ASIC => ASICTarget""".stripMargin
)
}
it should "require that all cases are part of the same option" in {
object Performance extends Group {
object Fast extends Case
object Small extends Case
}
class MixedOptions
extends ModuleWithChoice(new VerifTarget)(
Seq(Platform.FPGA -> new FPGATarget, Performance.Fast -> new ASICTarget)
)
intercept[IllegalArgumentException] { ChiselStage.emitCHIRRTL(new MixedOptions) }.getMessage() should include(
"cannot mix choices from different groups: Platform, Performance"
)
}
it should "require that at least one alternative is present" in {
class NoAlternatives extends ModuleWithChoice(new VerifTarget)(Seq())
intercept[IllegalArgumentException] { ChiselStage.emitCHIRRTL(new NoAlternatives) }.getMessage() should include(
"at least one alternative must be specified"
)
}
it should "allow a subset of options to be provided" in {
class SubsetOptions extends ModuleWithChoice(new VerifTarget)(Seq(Platform.FPGA -> new FPGATarget))
// Note, because of a quirk in how [[Case]]s are registered, only those referenced
// in the Module here are going to be captured. This will be fixed in a forthcoming PR
// that implements an [[addLayer]] like feature for [[Group]]s
ChiselStage
.emitCHIRRTL(new SubsetOptions)
.fileCheck()(
"""|CHECK: option Platform :
|CHECK-NEXT: FPGA
|CHECK: instchoice inst of VerifTarget, Platform :
|CHECK-NEXT: FPGA => FPGATarget""".stripMargin
)
}
it should "require that all cases are distinct" in {
class MixedOptions
extends ModuleWithChoice(new VerifTarget)(Seq(Platform.FPGA -> new FPGATarget, Platform.FPGA -> new ASICTarget))
intercept[IllegalArgumentException] { ChiselStage.emitCHIRRTL(new MixedOptions) }.getMessage() should include(
"duplicate case 'FPGA'"
)
}
it should "require that all IO bundles are type equivalent" in {
class Target16 extends FixedIOExtModule[TargetIO](new TargetIO(16))
class MixedIO extends ModuleWithChoice(new VerifTarget)(Seq(Platform.FPGA -> new Target16))
intercept[ChiselException] { ChiselStage.emitCHIRRTL(new MixedIO, Array("--throw-on-first-error")) }
.getMessage() should include(
"choice module IO bundles are not type equivalent"
)
}
it should "support bulk connections to instance choice IO" in {
class ModuleWithBulkConnect extends Module {
val io = IO(new TargetIO(8))
val inst = ModuleChoice(new VerifTarget)(Seq(Platform.FPGA -> new FPGATarget, Platform.ASIC -> new ASICTarget))
io <> inst
}
ChiselStage
.emitCHIRRTL(new ModuleWithBulkConnect)
.fileCheck()(
"""|CHECK: instchoice inst of VerifTarget, Platform :
|CHECK: connect io.out, inst.out
|CHECK: connect inst.in, io.in""".stripMargin
)
}
it should "generate correct FIRRTL when using tuple ports" in {
class Bar extends FixedIORawModule[(UInt, UInt)]((UInt(1.W), UInt(2.W)))
class Foo extends Module {
val a = IO(Output(UInt(1.W)))
val b = IO(Output(UInt(2.W)))
private val bar = ModuleChoice(new Bar)(Seq(Platform.FPGA -> new Bar))
a :<= bar._1
b :<= bar._2
}
ChiselStage.emitCHIRRTL(new Foo)
.fileCheck()(
"""|CHECK: instchoice bar of Bar
|CHECK: connect a, bar._1
|CHECK-NEXT: connect b, bar._2
|"""
)
}
}