The Chisel plugin provides some operations that are too difficult, or not possbile, to implement through regular Scala code.
These are the two things that the compile plugin does.
- Automatically generates the
cloneType
methods of Bundle - Changes the underlying mechanics of the
Bundle
selements
method in a way that does not require the use of reflection - Future work: Make having a Seq[Data] in a bundle be a compiler error. See "Detecting Bundles with Seq[Data]" below.
As of Mar 18, 2021, PR #1826, generating the cloneType
method (1. above) is now the default behavior.
The cloneType method used to be a tricky thing to write for chisel developers.
For historical purposes, here is the flag was used to control that prior to full adoption.
-P:chiselplugin:useBundlePlugin
A Bundle
has a default elements
method that relies on reflection, which is slow and brittle, to access the list of
fields the bundle contains.
When enabled this second operation of the plugin examines
the Bundle
s AST in order to determine the fields and then re-writes the underlying code of elements
.
Technically, rewriting a lower level private method _elementsImpl
.
It is expected that the using this feature will shortly become the default.
The plugin should not be enabled for the
main
chisel3 project because of internal considerations. It is enabled for theTest
section.
In the meantime, advanced users can try using the feature by adding the following flag to the scalac options in their chisel projects.
-P:chiselplugin:buildElementAccessor
For example in an build.sbt
file adding the line
scalacOptions += "-P:chiselplugin:genBundleElements",
in the appropriate place.
Trying to have a val Seq[Data]
(as opposed to a val Vec[Data]
in a Bundle
is a run time error.
Here is a block of code that could be added to the plugin to detect this case at compile time (with some refinement in
the detection mechanism):
if (member.isAccessor && typeIsSeqOfData(member.tpe) && !isIgnoreSeqInBundle(bundleSymbol)) {
global.reporter.error(
member.pos,
s"Bundle.field ${bundleSymbol.name}.${member.name} cannot be a Seq[Data]. " +
"Use Vec or MixedVec or mix in trait IgnoreSeqInBundle"
)
}
In general the easiest way to develop and debug new code in the plugin is to use println
statements.
Naively this can result in reams of text that can be very hard to look through.
What I found to be useful was creating some wrappers for println
that only printed when the Bundles
had a particular name pattern.
- Create a regular expression string in the
BundleComponent
class - Add a printf wrapper name
show
that checks theBundle
's name against the regex - For recursive code in
getAllBundleFields
create a different wrapperindentShow
that indents debug lines - Sprinkle calls to these wrappers as needed for debugging
val bundleNameDebugRegex = "MyBundle.*"
show
should be inside case bundle
block of the transform
method in order to have access to the current Bundle
def show(string: => String): Unit = {
if (bundle.symbol.name.toString.matches(bundleNameDebugRegex)) {
println(string)
}
}
This method can be added into BundleComponent.scala
in the transform
method after case Bundle
Inside of getAllBundleFields
I added the following code that indented for each recursion up the current
Bundle
's hierarchy.
def indentShow(s: => String): Unit = {
val indentString = ("-" * depth) * 2 + "> "
s.split("\n").foreach { line =>
show(indentString + line)
}
}