Skip to content

Commit 8498293

Browse files
authored
[chiselsim] Add a "flag" CLI option factory (#4880)
Add another factory for creating options that is intended to be used for creating "flag"-style options. This exists to unify this pattern as opposed to forcing users to invent their own when they need it. As can be seen, this unifies a number of existing flag-like options relating to waveform emission. CC: @andrew-gouldey-sifive: This will be available in the next internal Chisel release for your use. Signed-off-by: Schuyler Eldridge <[email protected]>
1 parent 669bca2 commit 8498293

File tree

3 files changed

+122
-118
lines changed

3 files changed

+122
-118
lines changed

docs/src/explanations/testing.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -322,11 +322,11 @@ can add a custom option to your test using one of several methods provided in
322322
the simulation including the Chisel elaboration, FIRRTL compilation, or generic
323323
or backend-specific settings.
324324

325-
More commonly, you just want to add an integer, double, or string option to a
326-
test. For this, simpler options
327-
(`chisel3.simulator.scalatest.CliOption.{simple, double, int, string}`) are
328-
provided. After an option has been declared, it can be accessed _within a test_
329-
using the `getOption` method.
325+
More commonly, you just want to add an integer, double, string, or flag-like
326+
options to a test. For this, simpler option _factories_
327+
(`chisel3.simulator.scalatest.CliOption.{simple, double, int, string, flag}`)
328+
are provided. After an option has been declared, it can be accessed _within a
329+
test_ using the `getOption` method.
330330

331331
:::warning
332332

src/main/scala/chisel3/simulator/scalatest/Cli.scala

Lines changed: 87 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -55,52 +55,44 @@ object Cli {
5555
trait EmitFsdb { this: HasCliOptions =>
5656

5757
addOption(
58-
CliOption[Unit](
59-
name = "emitFsdb",
60-
help = "compile with FSDB waveform support and start dumping waves at time zero",
61-
convert = value => {
62-
val trueValue = Set("true", "1")
63-
trueValue.contains(value) match {
64-
case true => ()
65-
case false =>
66-
throw new IllegalArgumentException(
67-
s"""invalid argument '$value' for option 'emitFsdb', must be one of ${trueValue
68-
.mkString("[", ", ", "]")}"""
69-
) with NoStackTrace
70-
}
71-
},
72-
updateChiselOptions = (_, a) => a,
73-
updateFirtoolOptions = (_, a) => a,
74-
updateCommonSettings = (_, options) => {
75-
options.copy(
76-
verilogPreprocessorDefines =
77-
options.verilogPreprocessorDefines :+ VerilogPreprocessorDefine(enableFsdbTracingSupport),
78-
simulationSettings = options.simulationSettings.copy(
79-
enableWavesAtTimeZero = true
58+
CliOption
59+
.flag(
60+
name = "emitFsdb",
61+
help = "compile with FSDB waveform support and start dumping waves at time zero"
62+
)
63+
.copy[Unit](
64+
updateChiselOptions = (_, a) => a,
65+
updateFirtoolOptions = (_, a) => a,
66+
updateCommonSettings = (_, options) => {
67+
options.copy(
68+
verilogPreprocessorDefines =
69+
options.verilogPreprocessorDefines :+ VerilogPreprocessorDefine(enableFsdbTracingSupport),
70+
simulationSettings = options.simulationSettings.copy(
71+
enableWavesAtTimeZero = true
72+
)
8073
)
81-
)
82-
},
83-
updateBackendSettings = (_, options) =>
84-
options match {
85-
case options: svsim.vcs.Backend.CompilationSettings =>
86-
options.copy(
87-
traceSettings = options.traceSettings.copy(fsdbSettings =
88-
Some(
89-
svsim.vcs.Backend.CompilationSettings.TraceSettings.FsdbSettings(
90-
sys.env.getOrElse(
91-
"VERDI_HOME",
92-
throw new RuntimeException(
93-
"Cannot enable FSDB support as the environment variable 'VERDI_HOME' was not set."
74+
},
75+
updateBackendSettings = (_, options) =>
76+
options match {
77+
case options: svsim.vcs.Backend.CompilationSettings =>
78+
options.copy(
79+
traceSettings = options.traceSettings.copy(fsdbSettings =
80+
Some(
81+
svsim.vcs.Backend.CompilationSettings.TraceSettings.FsdbSettings(
82+
sys.env.getOrElse(
83+
"VERDI_HOME",
84+
throw new RuntimeException(
85+
"Cannot enable FSDB support as the environment variable 'VERDI_HOME' was not set."
86+
)
9487
)
9588
)
9689
)
9790
)
9891
)
99-
)
100-
case options: svsim.verilator.Backend.CompilationSettings =>
101-
throw new IllegalArgumentException("Verilator does not support FSDB waveforms.")
102-
}
103-
)
92+
case options: svsim.verilator.Backend.CompilationSettings =>
93+
throw new IllegalArgumentException("Verilator does not support FSDB waveforms.")
94+
}
95+
)
10496
)
10597

10698
}
@@ -115,46 +107,36 @@ object Cli {
115107
trait EmitVcd { this: HasCliOptions =>
116108

117109
addOption(
118-
CliOption[Unit](
119-
name = "emitVcd",
120-
help = "compile with VCD waveform support and start dumping waves at time zero",
121-
convert = value => {
122-
val trueValue = Set("true", "1")
123-
trueValue.contains(value) match {
124-
case true => ()
125-
case false =>
126-
throw new IllegalArgumentException(
127-
s"""invalid argument '$value' for option 'emitVcd', must be one of ${trueValue
128-
.mkString("[", ", ", "]")}"""
129-
) with NoStackTrace
130-
}
131-
},
132-
updateChiselOptions = (_, a) => a,
133-
updateFirtoolOptions = (_, a) => a,
134-
updateCommonSettings = (_, options) => {
135-
options.copy(
136-
verilogPreprocessorDefines =
137-
options.verilogPreprocessorDefines :+ VerilogPreprocessorDefine(enableVcdTracingSupport),
138-
simulationSettings = options.simulationSettings.copy(
139-
enableWavesAtTimeZero = true
140-
)
141-
)
142-
},
143-
updateBackendSettings = (_, options) =>
144-
options match {
145-
case options: svsim.vcs.Backend.CompilationSettings =>
146-
options.copy(
147-
traceSettings = options.traceSettings.copy(enableVcd = true)
110+
CliOption
111+
.flag(name = "emitVcd", help = "compile with VCD waveform support and start dumping waves at time zero")
112+
.copy[Unit](
113+
updateChiselOptions = (_, a) => a,
114+
updateFirtoolOptions = (_, a) => a,
115+
updateCommonSettings = (_, options) => {
116+
options.copy(
117+
verilogPreprocessorDefines =
118+
options.verilogPreprocessorDefines :+ VerilogPreprocessorDefine(enableVcdTracingSupport),
119+
simulationSettings = options.simulationSettings.copy(
120+
enableWavesAtTimeZero = true
148121
)
149-
case options: svsim.verilator.Backend.CompilationSettings =>
150-
options.copy(
151-
traceStyle = options.traceStyle match {
152-
case None => Some(svsim.verilator.Backend.CompilationSettings.TraceStyle.Vcd(filename = "trace.vcd"))
153-
case alreadySet => alreadySet
154-
}
155-
)
156-
}
157-
)
122+
)
123+
},
124+
updateBackendSettings = (_, options) =>
125+
options match {
126+
case options: svsim.vcs.Backend.CompilationSettings =>
127+
options.copy(
128+
traceSettings = options.traceSettings.copy(enableVcd = true)
129+
)
130+
case options: svsim.verilator.Backend.CompilationSettings =>
131+
options.copy(
132+
traceStyle = options.traceStyle match {
133+
case None =>
134+
Some(svsim.verilator.Backend.CompilationSettings.TraceStyle.Vcd(filename = "trace.vcd"))
135+
case alreadySet => alreadySet
136+
}
137+
)
138+
}
139+
)
158140
)
159141

160142
}
@@ -172,41 +154,33 @@ object Cli {
172154
trait EmitVpd { this: HasCliOptions =>
173155

174156
addOption(
175-
CliOption[Unit](
176-
name = "emitVpd",
177-
help = "compile with VPD waveform support and start dumping waves at time zero",
178-
convert = value => {
179-
val trueValue = Set("true", "1")
180-
trueValue.contains(value) match {
181-
case true => ()
182-
case false =>
183-
throw new IllegalArgumentException(
184-
s"""invalid argument '$value' for option 'emitVpd', must be one of ${trueValue
185-
.mkString("[", ", ", "]")}"""
186-
) with NoStackTrace
187-
}
188-
},
189-
updateChiselOptions = (_, a) => a,
190-
updateFirtoolOptions = (_, a) => a,
191-
updateCommonSettings = (_, options) => {
192-
options.copy(
193-
verilogPreprocessorDefines =
194-
options.verilogPreprocessorDefines :+ VerilogPreprocessorDefine(enableVpdTracingSupport),
195-
simulationSettings = options.simulationSettings.copy(
196-
enableWavesAtTimeZero = true
197-
)
198-
)
199-
},
200-
updateBackendSettings = (_, options) =>
201-
options match {
202-
case options: svsim.vcs.Backend.CompilationSettings =>
203-
options.copy(
204-
traceSettings = options.traceSettings.copy(enableVpd = true)
157+
CliOption
158+
.flag(
159+
name = "emitVpd",
160+
help = "compile with VPD waveform support and start dumping waves at time zero"
161+
)
162+
.copy[Unit](
163+
updateChiselOptions = (_, a) => a,
164+
updateFirtoolOptions = (_, a) => a,
165+
updateCommonSettings = (_, options) => {
166+
options.copy(
167+
verilogPreprocessorDefines =
168+
options.verilogPreprocessorDefines :+ VerilogPreprocessorDefine(enableVpdTracingSupport),
169+
simulationSettings = options.simulationSettings.copy(
170+
enableWavesAtTimeZero = true
205171
)
206-
case options: svsim.verilator.Backend.CompilationSettings =>
207-
throw new IllegalArgumentException("Verilator does not support VPD waveforms.")
208-
}
209-
)
172+
)
173+
},
174+
updateBackendSettings = (_, options) =>
175+
options match {
176+
case options: svsim.vcs.Backend.CompilationSettings =>
177+
options.copy(
178+
traceSettings = options.traceSettings.copy(enableVpd = true)
179+
)
180+
case options: svsim.verilator.Backend.CompilationSettings =>
181+
throw new IllegalArgumentException("Verilator does not support VPD waveforms.")
182+
}
183+
)
210184
)
211185

212186
}

src/main/scala/chisel3/simulator/scalatest/HasCliOptions.scala

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,36 @@ object HasCliOptions {
113113
help = help,
114114
convert = identity
115115
)
116+
117+
/** Add a flag option to a test.
118+
*
119+
* This is an option which can only take one of two "truthy" values: `1` or
120+
* `true`. Any "falsey" values are not allowed. This option is a stand-in
121+
* for any option which is supposed to be a flag to a test which has some
122+
* effect if set.
123+
*
124+
* This option exists because Scalatest forces options to have a value. It
125+
* is illegal to pass an option like `-Dfoo`. This [[flag]] option exists
126+
* to problem a single flag-style option as opposed to having users roll
127+
* their own.
128+
*
129+
* @param name the name of the option
130+
* @param help help text to show to tell the user how to use this option
131+
*/
132+
def flag(name: String, help: String): CliOption[Unit] = simple[Unit](
133+
name = name,
134+
help = help,
135+
convert = value => {
136+
val trueValue = Set("true", "1")
137+
trueValue.contains(value) match {
138+
case true => ()
139+
case false =>
140+
throw new IllegalArgumentException(
141+
s"""invalid argument '$value' for option '$name', must be one of ${trueValue.mkString("[", ", ", "]")}"""
142+
) with NoStackTrace
143+
}
144+
}
145+
)
116146
}
117147

118148
}

0 commit comments

Comments
 (0)