-
Notifications
You must be signed in to change notification settings - Fork 602
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
VecLiterals First Pass #1793
VecLiterals First Pass #1793
Conversation
Making progress Lits can now be specified and pack Tests are being built - restored some BundleLit tests - working through a list of vec literal tests - adds a cloneWithWidth method to LitArg subclasses - Fixed problem with nested vec lits Vec literals tests pass A bit of cleanup Made bundle-literals support vec literals underneath
Remove println and add some scaladoc
# Conflicts: # core/src/main/scala/chisel3/Aggregate.scala # src/test/scala/chiselTests/ChiselSpec.scala
One test that broke is fixed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At a high level this seems sane, but a few comments.
Overall themes:
- I think there's code paths that can be shared and DRYed out with the bundle lits code
- It might make sense to keep the strictness / checks consistent with normal elements, instead of special casing strict checks in vec literal construction? Good alternatives might to be apply them everywhere universally (and perhaps the shared infrastructure can lead to cleaner code), or just remove them (especially if they're caught in FIRRTL). In general, I think consistency in behavior is best.
- Some style / cleanliness issues
case (Some(accumulator), Some(eltLit)) => | ||
val width = elt.width.get | ||
val masked = ((BigInt(1) << width) - 1) & eltLit // also handles the negative case with two's complement | ||
Some((accumulator << width) + masked) | ||
case (None, _) => None | ||
case (_, None) => None | ||
} | ||
|
||
// Shift the accumulated value by our width and add in our component, masked by width of Vec element. | ||
def shiftAddVec(accumulator: Option[BigInt], data: Data, elt: LitArg): Option[BigInt] = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This duplicates a lot of the logic above. I don't fully understand it (yet?), but it seems like perhaps with a bit more thought we might unify the two code paths?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reduced this to a single ShiftAdd for both Vec and Bundle
val bindingString = topBindingOpt match { | ||
case Some(VecLitBinding(vecLitBinding)) => | ||
val contents = vecLitBinding.map { case (data, lit) => | ||
s"$data=$lit" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure this does what we want it to do? Presumably, you want index=lit, but as is this seems like the index is going to be a ugly Data dump. Note that in Record.toString, it uses name from elements, then mixes it with the binding contents.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, now it shows indices, e.g. SInt<4>[2](0=SLit(1,<4>), 1=SLit(-2,<4>)
private[chisel3] def _makeLit(elementInitializers: (Int, Data)*): this.type = { | ||
|
||
// Returns pairs of all fields, element-level and containers, in a Record and their path names | ||
def getRecursiveFields(data: Data, path: String): Seq[(Data, String)] = data match { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should this be merged with Record._makeLit? It seems like a lot of helper functions share the same structure, and updates to both would be needed to support like Vecs in Bundles?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is a good idea. But I would not be very comfortable trying this right now. There's pretty much as many differences as there are similarities. Going DRY might break bundle lits in some subtle way, where as keeping it separate should keep any logic flaws limited to Vecs
case (x: Element, y: Element) => | ||
require(x typeEquivalent y) | ||
Seq(x -> y) | ||
case (x: Record, y: Record) => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In both the Record and Vec case we might want to check for typeEquivalent and element length equality, since zip will silently truncate
} | ||
|
||
def checkLiteralConstruction(): Unit = { | ||
val dupKeys = elementInitializers.map { x => x._1 }.groupBy(x => x).flatMap { case (k, v) => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are shorter ways to detect duplicates, comparing size against .distinct
or .toSet
https://stackoverflow.com/questions/7691971/easiest-way-to-decide-if-list-contains-duplicates
More set operations can probably get the duplicated keys.
You don't get the count, but I'd think the index is the important aspect.
* @param newWidth the new width for this | ||
* @return | ||
*/ | ||
def cloneWithWidth(newWidth: Width): this.type |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this needed? Is the root cause here that it's possible to specify a width in both the Data and the LitArg and those two can be out of sync? Do we need to do something special for VecLiteral that needs this new code?
@@ -47,6 +46,24 @@ class BundleLiteralSpec extends ChiselFlatSpec with Utils { | |||
} } | |||
} | |||
|
|||
"bundle literals" should "not pack when sparsely specified" in { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this have gone in its own PR? Doesn't look related to Vec literals?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
val notSameClass = !field.typeEquivalent(adjustedBitField) | ||
if (notSameClass) { // TODO typeEquivalent is too strict because it checks width | ||
throw new VecLiteralException( | ||
s"VecLit: Literal specified at index $fieldIndex ($value) does not match Vec type $sample_element" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we do these checks in the frontend elsewhere? If so, the code should be unified with that, and if not, I don't think it's a good idea to have mixed semantics
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not completely sure. In general I think errors should be reported as early as possible and at compile time over run time (or firrtl time) also when possible. I think the error messages can be more helpful with information that is possessed at earlier stages
@@ -123,3 +125,5 @@ sealed trait LitBinding extends UnconstrainedBinding with ReadOnlyBinding | |||
case class ElementLitBinding(litArg: LitArg) extends LitBinding | |||
// Literal binding attached to the root of a Bundle, containing literal values of its children. | |||
case class BundleLitBinding(litMap: Map[Data, LitArg]) extends LitBinding | |||
// Literal binding attached to the root of a Vec, containing literal values of its children. | |||
case class VecLitBinding(litMap: mutable.LinkedHashMap[Data, LitArg]) extends LitBinding |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this should be mutable. It might make sense to use mutable to build the final data structure, but the stored data structure should be immutable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Switched after generation to immutable.ListMap, important to maintain order
} | ||
|
||
value match { // Get the litArg(s) for this field | ||
case vecField: Vec[_] => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it make sense to keep the values consistent (value vs. vecField)? Otherwise it seems to be confusing to refer to either, when they're both the same thing?
convert from mutable.LinkedHashMap to immutable.ListMap after generation to preserve key ordering
But is this true: `defaulting any unconnected fields to 0 (regardless of type)` for either Bundles or Vec literals.
Added some mdoc for vec lits, plagiarized from bundle lits |
chisel3.stage.ChiselStage.emitVerilog(new Example3) | ||
``` | ||
|
||
Registers can be partially initialized from Vec literals. Only specified elements will be assigned. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does that mean that some registers will have reset values and some will not? Can you make that more clear in this sentence, whatever the answer is?
Closing this in favor of PR #1834 |
Add a Treadle build to the portion of CI that runs Chisel3 tests. Chisel3 needs to have a master copy of Treadle in order for it to work and cannot rely on resolution from Maven. Signed-off-by: Schuyler Eldridge <schuyler.eldridge@ibm.com>
Introduces a requested feature
Vec
literals. Much likeBundle
literals, this allowsdevelopers to specify a
Vec
aggregate literal in a convenient (relatively) compact forme.g.
Features
litOption
returns None)Reg
initializerVec
widthContributor Checklist
docs/src
?Type of Improvement
New feature
API Impact
This is an API addition. the
Vec
type now has aLit
method creates aVec
literal.Backend Code Generation Impact
This should not impact generated verilog
Desired Merge Strategy
Squash: The PR will be squashed and merged
Release Notes
Introduces Vec literals which are similar to Bundle Literals. Simple example:
Reviewer Checklist (only modified by reviewer)
Please Merge
?