summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChick Markley2021-04-27 12:17:17 -0700
committerGitHub2021-04-27 12:17:17 -0700
commit6deb379b1d8bafc81a605f60476bf0f24eac60b4 (patch)
treeb12c7dfaea1948ec9a7fa2f389db0699b3d1daf4
parent23b3fe8a6a2db92599bb0775626425056d47d1de (diff)
Introduce VecLiterals (#1834)
This PR provides for support for Vec literals. They can be one of two forms Inferred: ``` Vec.Lit(0x1.U, 0x2.U) ``` or explicit: ``` Vec(2, UInt(4.W)).Lit(0 -> 0x1.U, 1 -> 0x2.U) ``` - Explicit form allows for partial, or sparse, literals. - Vec literals can be used as Register initializers - Arbitrary nesting (consistent with type constraints is allowed)
-rw-r--r--core/src/main/scala/chisel3/Aggregate.scala274
-rw-r--r--core/src/main/scala/chisel3/Data.scala6
-rw-r--r--core/src/main/scala/chisel3/Element.scala4
-rw-r--r--core/src/main/scala/chisel3/experimental/package.scala33
-rw-r--r--core/src/main/scala/chisel3/internal/Binding.scala4
-rw-r--r--core/src/main/scala/chisel3/internal/firrtl/IR.scala24
-rw-r--r--docs/src/appendix/experimental-features.md82
-rw-r--r--src/test/scala/chiselTests/BundleLiteralSpec.scala23
-rw-r--r--src/test/scala/chiselTests/ChiselSpec.scala25
-rw-r--r--src/test/scala/chiselTests/VecLiteralSpec.scala526
10 files changed, 950 insertions, 51 deletions
diff --git a/core/src/main/scala/chisel3/Aggregate.scala b/core/src/main/scala/chisel3/Aggregate.scala
index df992bb9..c0b965b6 100644
--- a/core/src/main/scala/chisel3/Aggregate.scala
+++ b/core/src/main/scala/chisel3/Aggregate.scala
@@ -2,18 +2,19 @@
package chisel3
+import chisel3.experimental.VecLiterals.AddVecLiteralConstructor
+
import scala.collection.immutable.ListMap
import scala.collection.mutable.{HashSet, LinkedHashMap}
import scala.language.experimental.macros
-
-import chisel3.experimental.BaseModule
-import chisel3.experimental.BundleLiteralException
-import chisel3.experimental.EnumType
+import chisel3.experimental.{BaseModule, BundleLiteralException, ChiselEnum, EnumType, VecLiteralException}
import chisel3.internal._
import chisel3.internal.Builder.pushCommand
import chisel3.internal.firrtl._
import chisel3.internal.sourceinfo._
+import scala.collection.mutable
+
class AliasedAggregateFieldException(message: String) extends ChiselException(message)
/** An abstract class for data types that solely consist of (are an aggregate
@@ -51,16 +52,19 @@ sealed abstract class Aggregate extends Data {
*/
override def litOption: Option[BigInt] = {
// Shift the accumulated value by our width and add in our component, masked by our width.
- def shiftAdd(accumulator: Option[BigInt], elt: Data): Option[BigInt] = (accumulator, elt.litOption()) match {
- 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
+ def shiftAdd(accumulator: Option[BigInt], elt: Data): Option[BigInt] = {
+ (accumulator, elt.litOption()) match {
+ 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
+ }
}
+
topBindingOpt match {
- case Some(BundleLitBinding(_)) =>
+ case Some(BundleLitBinding(_)) | Some(VecLitBinding(_)) =>
getElements
.reverse
.foldLeft[Option[BigInt]](Some(BigInt(0)))(shiftAdd)
@@ -73,6 +77,7 @@ sealed abstract class Aggregate extends Data {
def getElements: Seq[Data]
private[chisel3] def width: Width = getElements.map(_.width).foldLeft(0.W)(_ + _)
+
private[chisel3] def legacyConnect(that: Data)(implicit sourceInfo: SourceInfo): Unit = {
// If the source is a DontCare, generate a DefInvalid for the sink,
// otherwise, issue a Connect.
@@ -83,11 +88,50 @@ sealed abstract class Aggregate extends Data {
}
}
+ // Returns pairs of all fields, element-level and containers, in a Record and their path names
+ private[chisel3] def getRecursiveFields(data: Data, path: String): Seq[(Data, String)] = data match {
+ case data: Record =>
+ data.elements.map { case (fieldName, fieldData) =>
+ getRecursiveFields(fieldData, s"$path.$fieldName")
+ }.fold(Seq(data -> path)) {
+ _ ++ _
+ }
+ case data: Vec[_] =>
+ data.getElements.zipWithIndex.map { case (fieldData, fieldIndex) =>
+ getRecursiveFields(fieldData, path = s"$path($fieldIndex)")
+ }.fold(Seq(data -> path)) {
+ _ ++ _
+ }
+ case data => Seq(data -> path) // we don't support or recurse into other Aggregate types here
+ }
+
+
+ // Returns pairs of corresponding fields between two Records of the same type
+ private[chisel3] def getMatchedFields(x: Data, y: Data): Seq[(Data, Data)] = (x, y) match {
+ case (x: Element, y: Element) =>
+ require(x typeEquivalent y)
+ Seq(x -> y)
+ case (x: Record, y: Record) =>
+ (x.elements zip y.elements).map { case ((xName, xElt), (yName, yElt)) =>
+ require(xName == yName) // assume fields returned in same, deterministic order
+ getMatchedFields(xElt, yElt)
+ }.fold(Seq(x -> y)) {
+ _ ++ _
+ }
+ case (x: Vec[_], y: Vec[_]) =>
+ (x.getElements zip y.getElements).map { case (xElt, yElt) =>
+ getMatchedFields(xElt, yElt)
+ }.fold(Seq(x -> y)) {
+ _ ++ _
+ }
+ }
+
override def do_asUInt(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = {
SeqUtils.do_asUInt(flatten.map(_.asUInt()))
}
+
private[chisel3] override def connectFromBits(that: Bits)(implicit sourceInfo: SourceInfo,
- compileOptions: CompileOptions): Unit = {
+ compileOptions: CompileOptions): Unit = {
var i = 0
val bits = if (that.isLit) that else WireDefault(UInt(this.width), that) // handles width padding
for (x <- flatten) {
@@ -155,9 +199,18 @@ trait VecFactory extends SourceInfoDoc {
*/
sealed class Vec[T <: Data] private[chisel3] (gen: => T, val length: Int)
extends Aggregate with VecLike[T] {
+
override def toString: String = {
+ val bindingString = topBindingOpt match {
+ case Some(VecLitBinding(vecLitBinding)) =>
+ val contents = vecLitBinding.zipWithIndex.map { case ((data, lit), index) =>
+ s"$index=$lit"
+ }.mkString(", ")
+ s"($contents)"
+ case _ => bindingToString
+ }
val elementType = sample_element.cloneType
- s"$elementType[$length]$bindingToString"
+ s"$elementType[$length]$bindingString"
}
private[chisel3] override def typeEquivalent(that: Data): Boolean = that match {
@@ -318,6 +371,154 @@ sealed class Vec[T <: Data] private[chisel3] (gen: => T, val length: Int)
}
curLayer(0)
}
+
+ /** Creates a Vec literal of this type with specified values. this must be a chisel type.
+ *
+ * @param elementInitializers literal values, specified as a pair of the Vec field to the literal value.
+ * The Vec field is specified as a function from an object of this type to the field.
+ * Fields that aren't initialized to DontCare, and assignment to a wire will overwrite any
+ * existing value with DontCare.
+ * @return a Vec literal of this type with subelement values specified
+ *
+ * Vec(2, UInt(8.W)).Lit(
+ * 1 -> 0x0A.U,
+ * 2 -> 0x0B.U
+ * )
+ * }}}
+ */
+ private[chisel3] def _makeLit(elementInitializers: (Int, T)*)(implicit sourceInfo: SourceInfo,
+ compileOptions: CompileOptions): this.type = {
+
+ def checkLiteralConstruction(): Unit = {
+ val dupKeys = elementInitializers.map { x => x._1 }.groupBy(x => x).flatMap { case (k, v) =>
+ if (v.length > 1) {
+ Some(k, v.length)
+ } else {
+ None
+ }
+ }
+ if (dupKeys.nonEmpty) {
+ throw new VecLiteralException(
+ s"VecLiteral: has duplicated indices ${dupKeys.map { case (k, n) => s"$k($n times)" }.mkString(",")}"
+ )
+ }
+
+ val outOfRangeIndices = elementInitializers.map(_._1).filter { case index => index < 0 || index >= length }
+ if (outOfRangeIndices.nonEmpty) {
+ throw new VecLiteralException(
+ s"VecLiteral: The following indices (${outOfRangeIndices.mkString(",")}) " +
+ s"are less than zero or greater or equal to than Vec length"
+ )
+ }
+ cloneSupertype(elementInitializers.map(_._2), s"Vec.Lit(...)")
+
+ // look for literals of this vec that are wider than the vec's type
+ val badLits = elementInitializers.flatMap {
+ case (index, lit) =>
+ (sample_element.width, lit.width) match {
+ case (KnownWidth(m), KnownWidth(n)) =>
+ if (m < n) Some(index -> lit) else None
+ case (KnownWidth(_), _) =>
+ None
+ case (UnknownWidth(), _) =>
+ None
+ case _ =>
+ Some(index -> lit)
+ }
+ case _ => None
+ }
+ if (badLits.nonEmpty) {
+ throw new VecLiteralException(
+ s"VecLiteral: Vec[$gen] has the following incorrectly typed or sized initializers: " +
+ badLits.map { case (a, b) => s"$a -> $b" }.mkString(",")
+ )
+ }
+
+ }
+
+ requireIsChiselType(this, "vec literal constructor model")
+ checkLiteralConstruction()
+
+ val clone = cloneType
+ val cloneFields = getRecursiveFields(clone, "(vec root)").toMap
+
+ // Create the Vec literal binding from litArgs of arguments
+ val vecLitLinkedMap = new mutable.LinkedHashMap[Data, LitArg]()
+ elementInitializers.sortBy { case (a, _) => a }.foreach { case (fieldIndex, value) =>
+ val field = clone.apply(fieldIndex)
+ val fieldName = cloneFields.getOrElse(field,
+ throw new VecLiteralException(s"field $field (with value $value) is not a field," +
+ s" ensure the field is specified as a function returning a field on an object of class ${this.getClass}," +
+ s" eg '_.a' to select hypothetical bundle field 'a'")
+ )
+
+ val valueBinding = value.topBindingOpt match {
+ case Some(litBinding: LitBinding) => litBinding
+ case _ => throw new VecLiteralException(s"field $fieldIndex specified with non-literal value $value")
+ }
+
+ field match { // Get the litArg(s) for this field
+ case bitField: Bits =>
+ if (!field.typeEquivalent(bitField)) {
+ throw new VecLiteralException(
+ s"VecLit: Literal specified at index $fieldIndex ($value) does not match Vec type $sample_element"
+ )
+ }
+ if (bitField.getWidth > field.getWidth) {
+ throw new VecLiteralException(
+ s"VecLit: Literal specified at index $fieldIndex ($value) is too wide for Vec type $sample_element"
+ )
+ }
+ val litArg = valueBinding match {
+ case ElementLitBinding(litArg) => litArg
+ case BundleLitBinding(litMap) => litMap.getOrElse(value,
+ throw new BundleLiteralException(s"Field $fieldName specified with unspecified value")
+ )
+ case VecLitBinding(litMap) => litMap.getOrElse(value,
+ throw new VecLiteralException(s"Field $fieldIndex specified with unspecified value"))
+ }
+ val adjustedLitArg = litArg.cloneWithWidth(sample_element.width)
+ vecLitLinkedMap(bitField) = adjustedLitArg
+
+ case recordField: Record =>
+ if (!(recordField.typeEquivalent(value))) {
+ throw new VecLiteralException(s"field $fieldIndex $recordField specified with non-type-equivalent value $value")
+ }
+ // Copy the source BundleLitBinding with fields (keys) remapped to the clone
+ val remap = getMatchedFields(value, recordField).toMap
+ valueBinding.asInstanceOf[BundleLitBinding].litMap.map { case (valueField, valueValue) =>
+ vecLitLinkedMap(remap(valueField)) = valueValue
+ }
+
+ case vecField: Vec[_] =>
+ if (!(vecField typeEquivalent value)) {
+ throw new VecLiteralException(s"field $fieldIndex $vecField specified with non-type-equivalent value $value")
+ }
+ // Copy the source VecLitBinding with vecFields (keys) remapped to the clone
+ val remap = getMatchedFields(value, vecField).toMap
+ value.topBinding.asInstanceOf[VecLitBinding].litMap.map { case (valueField, valueValue) =>
+ vecLitLinkedMap(remap(valueField)) = valueValue
+ }
+
+ case enumField: EnumType => {
+ if (!(enumField typeEquivalent value)) {
+ throw new VecLiteralException(s"field $fieldIndex $enumField specified with non-type-equivalent enum value $value")
+ }
+ val litArg = valueBinding match {
+ case ElementLitBinding(litArg) => litArg
+ case _ =>
+ throw new VecLiteralException(s"field $fieldIndex $enumField could not bematched with $valueBinding")
+ }
+ vecLitLinkedMap(field) = litArg
+ }
+
+ case _ => throw new VecLiteralException(s"unsupported field $fieldIndex of type $field")
+ }
+ }
+
+ clone.bind(VecLitBinding(ListMap(vecLitLinkedMap.toSeq:_*)))
+ clone
+ }
}
object VecInit extends SourceInfoDoc {
@@ -528,25 +729,6 @@ abstract class Record(private[chisel3] implicit val compileOptions: CompileOptio
* }}}
*/
private[chisel3] def _makeLit(elems: (this.type => (Data, 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 {
- case data: Record => data.elements.map { case (fieldName, fieldData) =>
- getRecursiveFields(fieldData, s"$path.$fieldName")
- }.fold(Seq(data -> path)) { _ ++ _ }
- case data => Seq(data -> path) // we don't support or recurse into other Aggregate types here
- }
-
- // Returns pairs of corresponding fields between two Records of the same type
- def getMatchedFields(x: Data, y: Data): Seq[(Data, Data)] = (x, y) match {
- case (x: Element, y: Element) =>
- require(x typeEquivalent y)
- Seq(x -> y)
- case (x: Record, y: Record) =>
- (x.elements zip y.elements).map { case ((xName, xElt), (yName, yElt)) =>
- require(xName == yName) // assume fields returned in same, deterministic order
- getMatchedFields(xElt, yElt)
- }.fold(Seq(x -> y)) { _ ++ _ }
- }
requireIsChiselType(this, "bundle literal constructor model")
val clone = cloneType
@@ -572,9 +754,15 @@ abstract class Record(private[chisel3] implicit val compileOptions: CompileOptio
val litArg = valueBinding match {
case ElementLitBinding(litArg) => litArg
case BundleLitBinding(litMap) => litMap.getOrElse(value,
- throw new BundleLiteralException(s"Field $fieldName specified with unspecified value"))
+ throw new BundleLiteralException(s"Field $fieldName specified with unspecified value")
+ )
+ case VecLitBinding(litMap) => litMap.getOrElse(value,
+ throw new VecLiteralException(s"Vec literal $fieldName specified with out literal values")
+ )
+
}
Seq(field -> litArg)
+
case field: Record =>
if (!(field typeEquivalent value)) {
throw new BundleLiteralException(s"field $fieldName $field specified with non-type-equivalent value $value")
@@ -584,18 +772,33 @@ abstract class Record(private[chisel3] implicit val compileOptions: CompileOptio
value.topBinding.asInstanceOf[BundleLitBinding].litMap.map { case (valueField, valueValue) =>
remap(valueField) -> valueValue
}
+
+ case vecField: Vec[_] =>
+ if (!(vecField typeEquivalent value)) {
+ throw new BundleLiteralException(s"field $fieldName $vecField specified with non-type-equivalent value $value")
+ }
+ // Copy the source BundleLitBinding with fields (keys) remapped to the clone
+ val remap = getMatchedFields(value, vecField).toMap
+ value.topBinding.asInstanceOf[VecLitBinding].litMap.map { case (valueField, valueValue) =>
+ remap(valueField) -> valueValue
+ }
+
case field: EnumType => {
if (!(field typeEquivalent value)) {
throw new BundleLiteralException(s"field $fieldName $field specified with non-type-equivalent enum value $value")
}
val litArg = valueBinding match {
case ElementLitBinding(litArg) => litArg
+ case _ =>
+ throw new BundleLiteralException(s"field $fieldName $field could not be matched with $valueBinding")
}
Seq(field -> litArg)
}
case _ => throw new BundleLiteralException(s"unsupported field $fieldName of type $field")
}
- } // don't convert to a Map yet to preserve duplicate keys
+ }
+
+ // don't convert to a Map yet to preserve duplicate keys
val duplicates = bundleLitMap.map(_._1).groupBy(identity).collect { case (x, elts) if elts.size > 1 => x }
if (!duplicates.isEmpty) {
val duplicateNames = duplicates.map(cloneFields(_)).mkString(", ")
@@ -694,6 +897,7 @@ class AutoClonetypeException(message: String) extends ChiselException(message)
package experimental {
class BundleLiteralException(message: String) extends ChiselException(message)
+ class VecLiteralException(message: String) extends ChiselException(message)
}
diff --git a/core/src/main/scala/chisel3/Data.scala b/core/src/main/scala/chisel3/Data.scala
index 377a94e6..0241f248 100644
--- a/core/src/main/scala/chisel3/Data.scala
+++ b/core/src/main/scala/chisel3/Data.scala
@@ -392,6 +392,7 @@ abstract class Data extends HasId with NamedComponent with SourceInfoDoc {
case Some(DontCareBinding()) => s"(DontCare)"
case Some(ElementLitBinding(litArg)) => s"(unhandled literal)"
case Some(BundleLitBinding(litMap)) => s"(unhandled bundle literal)"
+ case Some(VecLitBinding(litMap)) => s"(unhandled vec literal)"
}).getOrElse("")
// Return ALL elements at root of this type.
@@ -491,6 +492,11 @@ abstract class Data extends HasId with NamedComponent with SourceInfoDoc {
case Some(litArg) => litArg
case _ => materializeWire() // FIXME FIRRTL doesn't have Bundle literal expressions
}
+ case Some(VecLitBinding(litMap)) =>
+ litMap.get(this) match {
+ case Some(litArg) => litArg
+ case _ => materializeWire() // FIXME FIRRTL doesn't have Vec literal expressions
+ }
case Some(DontCareBinding()) =>
materializeWire() // FIXME FIRRTL doesn't have a DontCare expression so materialize a Wire
// Non-literals
diff --git a/core/src/main/scala/chisel3/Element.scala b/core/src/main/scala/chisel3/Element.scala
index 0c99ff70..40291b12 100644
--- a/core/src/main/scala/chisel3/Element.scala
+++ b/core/src/main/scala/chisel3/Element.scala
@@ -30,6 +30,10 @@ abstract class Element extends Data {
case Some(litArg) => Some(ElementLitBinding(litArg))
case _ => Some(DontCareBinding())
}
+ case Some(VecLitBinding(litMap)) => litMap.get(this) match {
+ case Some(litArg) => Some(ElementLitBinding(litArg))
+ case _ => Some(DontCareBinding())
+ }
case topBindingOpt => topBindingOpt
}
diff --git a/core/src/main/scala/chisel3/experimental/package.scala b/core/src/main/scala/chisel3/experimental/package.scala
index 4dc7ba4b..e8360430 100644
--- a/core/src/main/scala/chisel3/experimental/package.scala
+++ b/core/src/main/scala/chisel3/experimental/package.scala
@@ -2,6 +2,8 @@
package chisel3
+import chisel3.internal.sourceinfo.SourceInfo
+
/** Package for experimental features, which may have their API changed, be removed, etc.
*
* Because its contents won't necessarily have the same level of stability and support as
@@ -124,10 +126,39 @@ package object experimental {
object BundleLiterals {
implicit class AddBundleLiteralConstructor[T <: Record](x: T) {
- def Lit(elems: (T => (Data, Data))*): T = {
+ def Lit(elems: (T => (Data, Data))*)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = {
+ x._makeLit(elems: _*)
+ }
+ }
+ }
+
+ /** This class provides the `Lit` method needed to define a `Vec` literal
+ */
+ object VecLiterals {
+ implicit class AddVecLiteralConstructor[T <: Data](x: Vec[T]) {
+ /** Given a generator of a list tuples of the form [Int, Data]
+ * constructs a Vec literal, parallel concept to `BundleLiteral`
+ *
+ * @param elems tuples of an index and a literal value
+ * @return
+ */
+ def Lit(elems: (Int, T)*)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Vec[T] = {
x._makeLit(elems: _*)
}
}
+
+ implicit class AddObjectLiteralConstructor(x: Vec.type) {
+ /** This provides an literal construction method for cases using
+ * object `Vec` as in `Vec.Lit(1.U, 2.U)`
+ */
+ def Lit[T <: Data](elems: T*)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Vec[T] = {
+ require(elems.nonEmpty, s"Lit.Vec(...) must have at least one element")
+ val indexElements = elems.zipWithIndex.map { case (element, index) => (index, element)}
+ val widestElement = elems.maxBy(_.getWidth)
+ val vec: Vec[T] = Vec.apply(indexElements.length, chiselTypeOf(widestElement))
+ vec.Lit(indexElements:_*)
+ }
+ }
}
// Use to add a prefix to any component generated in input scope
diff --git a/core/src/main/scala/chisel3/internal/Binding.scala b/core/src/main/scala/chisel3/internal/Binding.scala
index 9e17aded..8a3c4330 100644
--- a/core/src/main/scala/chisel3/internal/Binding.scala
+++ b/core/src/main/scala/chisel3/internal/Binding.scala
@@ -6,6 +6,8 @@ import chisel3._
import chisel3.experimental.BaseModule
import chisel3.internal.firrtl.LitArg
+import scala.collection.immutable.ListMap
+
/** Requires that a node is hardware ("bound")
*/
object requireIsHardware {
@@ -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: ListMap[Data, LitArg]) extends LitBinding
diff --git a/core/src/main/scala/chisel3/internal/firrtl/IR.scala b/core/src/main/scala/chisel3/internal/firrtl/IR.scala
index 61f97ce6..81b4f7ab 100644
--- a/core/src/main/scala/chisel3/internal/firrtl/IR.scala
+++ b/core/src/main/scala/chisel3/internal/firrtl/IR.scala
@@ -91,6 +91,14 @@ abstract class LitArg(val num: BigInt, widthArg: Width) extends Arg {
elem
}
+ /** Provides a mechanism that LitArgs can have their width adjusted
+ * to match other members of a VecLiteral
+ *
+ * @param newWidth the new width for this
+ * @return
+ */
+ def cloneWithWidth(newWidth: Width): this.type
+
protected def minWidth: Int
if (forcedWidth) {
require(widthArg.get >= minWidth,
@@ -106,6 +114,10 @@ case class ULit(n: BigInt, w: Width) extends LitArg(n, w) {
def name: String = "UInt" + width + "(\"h0" + num.toString(16) + "\")"
def minWidth: Int = 1 max n.bitLength
+ def cloneWithWidth(newWidth: Width): this.type = {
+ ULit(n, newWidth).asInstanceOf[this.type]
+ }
+
require(n >= 0, s"UInt literal ${n} is negative")
}
@@ -115,6 +127,10 @@ case class SLit(n: BigInt, w: Width) extends LitArg(n, w) {
s"asSInt(${ULit(unsigned, width).name})"
}
def minWidth: Int = 1 + n.bitLength
+
+ def cloneWithWidth(newWidth: Width): this.type = {
+ SLit(n, newWidth).asInstanceOf[this.type]
+ }
}
case class FPLit(n: BigInt, w: Width, binaryPoint: BinaryPoint) extends LitArg(n, w) {
@@ -123,6 +139,10 @@ case class FPLit(n: BigInt, w: Width, binaryPoint: BinaryPoint) extends LitArg(n
s"asFixedPoint(${ULit(unsigned, width).name}, ${binaryPoint.asInstanceOf[KnownBinaryPoint].value})"
}
def minWidth: Int = 1 + n.bitLength
+
+ def cloneWithWidth(newWidth: Width): this.type = {
+ FPLit(n, newWidth, binaryPoint).asInstanceOf[this.type]
+ }
}
case class IntervalLit(n: BigInt, w: Width, binaryPoint: BinaryPoint) extends LitArg(n, w) {
@@ -135,6 +155,10 @@ case class IntervalLit(n: BigInt, w: Width, binaryPoint: BinaryPoint) extends Li
IntervalRange.getBound(isClosed = true, BigDecimal(n)), IntervalRange.getRangeWidth(binaryPoint))
}
def minWidth: Int = 1 + n.bitLength
+
+ def cloneWithWidth(newWidth: Width): this.type = {
+ IntervalLit(n, newWidth, binaryPoint).asInstanceOf[this.type]
+ }
}
case class Ref(name: String) extends Arg
diff --git a/docs/src/appendix/experimental-features.md b/docs/src/appendix/experimental-features.md
index 363f7a06..4b1208aa 100644
--- a/docs/src/appendix/experimental-features.md
+++ b/docs/src/appendix/experimental-features.md
@@ -85,7 +85,87 @@ class Example3 extends RawModule {
chisel3.stage.ChiselStage.emitVerilog(new Example3)
```
-Vec literals are not yet supported.
+### Vec Literals
+
+Vec literals are very similar to Bundle literals and can be constructed via an experimental import.
+They can be constructed in two forms, with type and length inferred as in:
+
+```scala mdoc
+import chisel3._
+import chisel3.experimental.VecLiterals._
+
+class VecExample1 extends Module {
+ val out = IO(Output(Vec(2, UInt(4.W))))
+ out := Vec.Lit(0xa.U, 0xbb.U)
+}
+```
+```scala mdoc:verilog
+chisel3.stage.ChiselStage.emitVerilog(new VecExample1)
+```
+
+or explicitly as in:
+
+```scala mdoc
+import chisel3._
+import chisel3.experimental.VecLiterals._
+
+class VecExample1a extends Module {
+ val out = IO(Output(Vec(2, UInt(4.W))))
+ out := Vec(2, UInt(4.W)).Lit(0 -> 1.U, 1 -> 2.U)
+}
+```
+
+```scala mdoc:verilog
+chisel3.stage.ChiselStage.emitVerilog(new VecExample1a)
+```
+
+The following examples all use the explicit form.
+With the explicit form partial specification is allowed.
+When used with as a `Reg` `reset` value, only specified indices of the `Reg`'s `Vec`
+will be reset
+
+```scala mdoc
+class VecExample2 extends RawModule {
+ val out = IO(Output(Vec(4, UInt(4.W))))
+ out := Vec(4, UInt(4.W)).Lit(0 -> 1.U, 3 -> 7.U)
+}
+```
+
+```scala mdoc:verilog
+chisel3.stage.ChiselStage.emitVerilog(new VecExample2)
+```
+
+Registers can be initialized from Vec literals
+
+```scala mdoc
+class VecExample3 extends Module {
+ val out = IO(Output(Vec(4, UInt(8.W))))
+ val y = RegInit(
+ Vec(4, UInt(8.W)).Lit(0 -> 0xAB.U(8.W), 1 -> 0xCD.U(8.W), 2 -> 0xEF.U(8.W), 3 -> 0xFF.U(8.W))
+ )
+ out := y
+}
+```
+
+```scala mdoc:verilog
+chisel3.stage.ChiselStage.emitVerilog(new VecExample3)
+```
+
+Vec literals can also be nested arbitrarily.
+
+```scala mdoc
+class VecExample5 extends RawModule {
+ val out = IO(Output(Vec(2, new ChildBundle)))
+ out := Vec(2, new ChildBundle).Lit(
+ 0 -> (new ChildBundle).Lit(_.foo -> 42.U),
+ 1 -> (new ChildBundle).Lit(_.foo -> 7.U)
+ )
+}
+```
+
+```scala mdoc:verilog
+chisel3.stage.ChiselStage.emitVerilog(new VecExample5)
+```
### Interval Type <a name="interval-type"></a>
diff --git a/src/test/scala/chiselTests/BundleLiteralSpec.scala b/src/test/scala/chiselTests/BundleLiteralSpec.scala
index 2a3ce2c9..b4adde4a 100644
--- a/src/test/scala/chiselTests/BundleLiteralSpec.scala
+++ b/src/test/scala/chiselTests/BundleLiteralSpec.scala
@@ -6,9 +6,8 @@ import chisel3._
import chisel3.stage.ChiselStage
import chisel3.testers.BasicTester
import chisel3.experimental.BundleLiterals._
-import chisel3.experimental.BundleLiteralException
-import chisel3.experimental.ChiselEnum
-import chisel3.experimental.FixedPoint
+import chisel3.experimental.VecLiterals.AddVecLiteralConstructor
+import chisel3.experimental.{BundleLiteralException, ChiselEnum, ChiselRange, FixedPoint, Interval}
class BundleLiteralSpec extends ChiselFlatSpec with Utils {
object MyEnum extends ChiselEnum {
@@ -76,6 +75,24 @@ class BundleLiteralSpec extends ChiselFlatSpec with Utils {
} }
}
+ "bundle literals of vec literals" should "work" in {
+ assertTesterPasses(new BasicTester {
+ val range = range"[0,4].2"
+ val bundleWithVecs = new Bundle {
+ val a = Vec(2, UInt(4.W))
+ val b = Vec(2, Interval(range))
+ }.Lit(
+ _.a -> Vec(2, UInt(4.W)).Lit(0 -> 0xA.U, 1 -> 0xB.U),
+ _.b -> Vec(2, Interval(range)).Lit(0 -> (1.5).I(range), 1 -> (0.25).I(range))
+ )
+ chisel3.assert(bundleWithVecs.a(0) === 0xA.U)
+ chisel3.assert(bundleWithVecs.a(1) === 0xB.U)
+ chisel3.assert(bundleWithVecs.b(0) === (1.5).I(range))
+ chisel3.assert(bundleWithVecs.b(1) === (0.25).I(range))
+ stop()
+ })
+ }
+
"partial bundle literals" should "work in RTL" in {
assertTesterPasses{ new BasicTester{
val bundleLit = (new MyBundle).Lit(_.a -> 42.U)
diff --git a/src/test/scala/chiselTests/ChiselSpec.scala b/src/test/scala/chiselTests/ChiselSpec.scala
index 8df680d6..9503089a 100644
--- a/src/test/scala/chiselTests/ChiselSpec.scala
+++ b/src/test/scala/chiselTests/ChiselSpec.scala
@@ -2,22 +2,22 @@
package chiselTests
-import org.scalatest._
-import org.scalatest.prop._
-import org.scalatest.flatspec.AnyFlatSpec
-import org.scalacheck._
import chisel3._
-import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage}
+import chisel3.aop.Aspect
+import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage, NoRunFirrtlCompilerAnnotation, PrintFullStackTraceAnnotation}
import chisel3.testers._
-import firrtl.{AnnotationSeq, CommonOptions, EmittedVerilogCircuitAnnotation, ExecutionOptionsManager, FirrtlExecutionFailure, FirrtlExecutionSuccess, HasFirrtlOptions}
-import firrtl.annotations.{Annotation, DeletedAnnotation}
+import firrtl.annotations.Annotation
import firrtl.util.BackendCompilationUtilities
+import firrtl.{AnnotationSeq, EmittedVerilogCircuitAnnotation}
+import org.scalacheck._
+import org.scalatest._
+import org.scalatest.flatspec.AnyFlatSpec
+import org.scalatest.freespec.AnyFreeSpec
+import org.scalatest.matchers.should._
+import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks
+
import java.io.ByteArrayOutputStream
import java.security.Permission
-
-import chisel3.aop.Aspect
-import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage, NoRunFirrtlCompilerAnnotation, PrintFullStackTraceAnnotation}
-import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks
import scala.reflect.ClassTag
/** Common utility functions for Chisel unit tests. */
@@ -90,6 +90,9 @@ trait ChiselRunners extends Assertions with BackendCompilationUtilities {
/** Spec base class for BDD-style testers. */
abstract class ChiselFlatSpec extends AnyFlatSpec with ChiselRunners with Matchers
+/** Spec base class for BDD-style testers. */
+abstract class ChiselFreeSpec extends AnyFreeSpec with ChiselRunners with Matchers
+
/** Spec base class for property-based testers. */
abstract class ChiselPropSpec extends PropSpec with ChiselRunners with ScalaCheckPropertyChecks with Matchers {
diff --git a/src/test/scala/chiselTests/VecLiteralSpec.scala b/src/test/scala/chiselTests/VecLiteralSpec.scala
new file mode 100644
index 00000000..d11289e1
--- /dev/null
+++ b/src/test/scala/chiselTests/VecLiteralSpec.scala
@@ -0,0 +1,526 @@
+// SPDX-License-Identifier: Apache-2.0
+
+package chiselTests
+
+import chisel3._
+import chisel3.experimental.BundleLiterals.AddBundleLiteralConstructor
+import chisel3.experimental.VecLiterals._
+import chisel3.experimental.{ChiselEnum, FixedPoint, VecLiteralException}
+import chisel3.stage.ChiselStage
+import chisel3.testers.BasicTester
+import chisel3.util.Counter
+import scala.language.reflectiveCalls
+
+class VecLiteralSpec extends ChiselFreeSpec with Utils {
+ object MyEnum extends ChiselEnum {
+ val sA, sB, sC = Value
+ }
+ object MyEnumB extends ChiselEnum {
+ val sA, sB = Value
+ }
+
+ "Vec literals should work with chisel Enums" in {
+ val enumVec = Vec(3, MyEnum()).Lit(0 -> MyEnum.sA, 1 -> MyEnum.sB, 2-> MyEnum.sC)
+ enumVec(0).toString should include (MyEnum.sA.toString)
+ enumVec(1).toString should include (MyEnum.sB.toString)
+ enumVec(2).toString should include (MyEnum.sC.toString)
+ }
+
+ "improperly constructed vec literals should be detected" - {
+ "indices in vec literal muse be greater than zero and less than length" in {
+ val e = intercept[VecLiteralException] {
+ Vec(2, UInt(4.W)).Lit(0 -> 1.U, 1 -> 2.U, 2 -> 3.U, 3 -> 4.U, -2 -> 7.U)
+ }
+ e.getMessage should include (
+ "VecLiteral: The following indices (2,3,-2) are less than zero or greater or equal to than Vec length"
+ )
+ }
+
+ "indices in vec literals must not be repeated" in {
+ val e = intercept[VecLiteralException] {
+ Vec(2, UInt(4.W)).Lit(0 -> 1.U, 1 -> 2.U, 2 -> 3.U, 2 -> 3.U, 2 -> 3.U, 3 -> 4.U)
+ }
+ e.getMessage should include("VecLiteral: has duplicated indices 2(3 times)")
+ }
+ "lits must fit in vec element width" in {
+ val e = intercept[VecLiteralException] {
+ Vec(2, SInt(4.W)).Lit(0 -> 0xab.S, 1 -> 0xbc.S)
+ }
+ e.getMessage should include(
+ "VecLiteral: Vec[SInt<4>] has the following incorrectly typed or sized initializers: " +
+ "0 -> SInt<9>(171),1 -> SInt<9>(188)"
+ )
+ }
+
+ "all lits must be the same type but width can be equal or smaller than the Vec's element width" in {
+ val v = Vec(2, SInt(4.W)).Lit(0 -> 1.S, 1 -> -2.S)
+ v(0).toString should include(1.S(4.W).toString)
+ v(1).toString should include((-2).S(4.W).toString)
+ v.toString should include ("SInt<4>[2](0=SLit(1,<4>), 1=SLit(-2,<4>)")
+ }
+
+ "all lits must be the same type but width cannot be greater than Vec's element width" in {
+ val e = intercept[VecLiteralException] {
+ val v = Vec(2, SInt(4.W)).Lit(0 -> 11.S, 1 -> -0xffff.S)
+ }
+ e.getMessage should include(
+ "VecLiteral: Vec[SInt<4>] has the following incorrectly typed or sized initializers: 0 -> SInt<5>(11),1 -> SInt<17>(-65535)"
+ )
+ }
+ }
+
+ //NOTE: I had problems where this would not work if this class declaration was inside test scope
+ class HasVecInit extends Module {
+ val initValue = Vec(4, UInt(8.W)).Lit(0 -> 0xAB.U(8.W), 1 -> 0xCD.U(8.W), 2 -> 0xEF.U(8.W), 3 -> 0xFF.U(8.W))
+ val y = RegInit(initValue)
+ }
+
+ "Vec literals should work when used to initialize a reg of vec" in {
+ val firrtl = (new ChiselStage).emitFirrtl(new HasVecInit, args = Array("--full-stacktrace"))
+ firrtl should include("""_y_WIRE[0] <= UInt<8>("hab")""")
+ firrtl should include("""_y_WIRE[1] <= UInt<8>("hcd")""")
+ firrtl should include("""_y_WIRE[2] <= UInt<8>("hef")""")
+ firrtl should include("""_y_WIRE[3] <= UInt<8>("hff")""")
+ firrtl should include(""" reset => (reset, _y_WIRE)""".stripMargin)
+ }
+
+ //NOTE: I had problems where this would not work if this class declaration was inside test scope
+ class HasPartialVecInit extends Module {
+ val initValue = Vec(4, UInt(8.W)).Lit(0 -> 0xAB.U(8.W), 2 -> 0xEF.U(8.W), 3 -> 0xFF.U(8.W))
+ val y = RegInit(initValue)
+ }
+
+ "Vec literals should work when used to partially initialize a reg of vec" in {
+ val firrtl = (new ChiselStage).emitFirrtl(new HasPartialVecInit, args = Array("--full-stacktrace"))
+ firrtl should include("""_y_WIRE[0] <= UInt<8>("hab")""")
+ firrtl should include("""_y_WIRE[1] is invalid""")
+ firrtl should include("""_y_WIRE[2] <= UInt<8>("hef")""")
+ firrtl should include("""_y_WIRE[3] <= UInt<8>("hff")""")
+ firrtl should include(""" reset => (reset, _y_WIRE)""".stripMargin)
+ }
+
+ class ResetRegWithPartialVecLiteral extends Module {
+ val in = IO(Input(Vec(4, UInt(8.W))))
+ val out = IO(Output(Vec(4, UInt(8.W))))
+ val initValue = Vec(4, UInt(8.W)).Lit(0 -> 0xAB.U(8.W), 2 -> 0xEF.U(8.W), 3 -> 0xFF.U(8.W))
+ val y = RegInit(initValue)
+ when(in(1) > 0.U) {
+ y(1) := in(1)
+ }
+ when(in(2) > 0.U) {
+ y(2) := in(2)
+ }
+ out := y
+ }
+
+ "Vec literals should only init specified fields when used to partially initialize a reg of vec" in {
+ println(ChiselStage.emitFirrtl(new ResetRegWithPartialVecLiteral))
+ assertTesterPasses(new BasicTester {
+ val m = Module(new ResetRegWithPartialVecLiteral)
+ val (counter, wrapped) = Counter(true.B, 8)
+ m.in := DontCare
+ when(counter < 2.U) {
+ m.in(1) := 0xff.U
+ m.in(2) := 0xff.U
+ }.elsewhen(counter === 2.U) {
+ chisel3.assert(m.out(1) === 0xff.U)
+ chisel3.assert(m.out(2) === 0xff.U)
+ }.elsewhen(counter === 3.U) {
+ m.in(1) := 0.U
+ m.in(2) := 0.U
+ m.reset := true.B
+ }.elsewhen(counter > 2.U) {
+ // m.out(1) should not be reset, m.out(2) should be reset
+ chisel3.assert(m.out(1) === 0xff.U)
+ chisel3.assert(m.out(2) === 0xEF.U)
+ }
+ when(wrapped) {
+ stop()
+ }
+ })
+ }
+
+ "lowest of vec literal contains least significant bits and " in {
+ val y = Vec(4, UInt(8.W)).Lit(0 -> 0xAB.U(8.W), 1 -> 0xCD.U(8.W), 2 -> 0xEF.U(8.W), 3 -> 0xFF.U(8.W))
+ y.litValue() should be(BigInt("FFEFCDAB", 16))
+ }
+
+ "the order lits are specified does not matter" in {
+ val y = Vec(4, UInt(8.W)).Lit(3 -> 0xFF.U(8.W), 2 -> 0xEF.U(8.W), 1 -> 0xCD.U(8.W), 0 -> 0xAB.U(8.W))
+ y.litValue() should be(BigInt("FFEFCDAB", 16))
+ }
+
+ "regardless of the literals widths, packing should be done based on the width of the Vec's gen" in {
+ val z = Vec(4, UInt(8.W)).Lit(0 -> 0x2.U, 1 -> 0x2.U, 2 -> 0x2.U, 3 -> 0x3.U)
+ z.litValue() should be(BigInt("03020202", 16))
+ }
+
+ "packing sparse vec lits should not pack, litOption returns None" in {
+ // missing sub-listeral for index 2
+ val z = Vec(4, UInt(8.W)).Lit(0 -> 0x2.U, 1 -> 0x2.U, 3 -> 0x3.U)
+
+ z.litOption should be(None)
+ }
+
+ "registers can be initialized with a Vec literal" in {
+ assertTesterPasses(new BasicTester {
+ val y = RegInit(Vec(4, UInt(8.W)).Lit(0 -> 0xAB.U(8.W), 1 -> 0xCD.U(8.W), 2 -> 0xEF.U(8.W), 3 -> 0xFF.U(8.W)))
+ chisel3.assert(y.asUInt === BigInt("FFEFCDAB", 16).U)
+ stop()
+ })
+ }
+
+ "how does asUInt work" in {
+ assertTesterPasses(new BasicTester {
+ val vec1 = Vec(4, UInt(16.W)).Lit(0 -> 0xDD.U, 1 -> 0xCC.U, 2 -> 0xBB.U, 3 -> 0xAA.U)
+
+ val vec2 = VecInit(Seq(0xDD.U, 0xCC.U, 0xBB.U, 0xAA.U))
+ printf("vec1 %x\n", vec1.asUInt())
+ printf("vec2 %x\n", vec2.asUInt())
+ stop()
+ })
+ }
+
+ "Vec literals uint conversion" in {
+ class M1 extends Module {
+ val out1 = IO(Output(UInt(64.W)))
+ val out2 = IO(Output(UInt(64.W)))
+
+ val v1 = Vec(4, UInt(16.W)).Lit(0 -> 0xDD.U, 1 -> 0xCC.U, 2 -> 0xBB.U, 3 -> 0xAA.U)
+ out1 := v1.asUInt
+
+ val v2 = VecInit(0xDD.U(16.W), 0xCC.U, 0xBB.U, 0xAA.U)
+ out2 := v2.asUInt
+ }
+
+ assertTesterPasses(new BasicTester {
+ val m = Module(new M1)
+ chisel3.assert(m.out1 === m.out2)
+ stop()
+ })
+ }
+
+ "VecLits should work properly with .asUInt" in {
+ val outsideVecLit = Vec(4, UInt(16.W)).Lit(0 -> 0xDD.U, 1 -> 0xCC.U, 2 -> 0xBB.U, 3 -> 0xAA.U)
+
+ assertTesterPasses {
+ new BasicTester {
+ chisel3.assert(outsideVecLit(0) === 0xDD.U, s"v(0)")
+ stop()
+ }
+ }
+ }
+
+ "bundle literals should work in RTL" in {
+ val outsideVecLit = Vec(4, UInt(16.W)).Lit(0 -> 0xDD.U, 1 -> 0xCC.U, 2 -> 0xBB.U, 3 -> 0xAA.U)
+
+ assertTesterPasses {
+ new BasicTester {
+ chisel3.assert(outsideVecLit(0) === 0xDD.U, s"v(0)")
+ chisel3.assert(outsideVecLit(1) === 0xCC.U)
+ chisel3.assert(outsideVecLit(2) === 0xBB.U)
+ chisel3.assert(outsideVecLit(3) === 0xAA.U)
+
+ chisel3.assert(outsideVecLit.litValue().U === outsideVecLit.asUInt())
+
+ val insideVecLit = Vec(4, UInt(16.W)).Lit(0 -> 0xDD.U, 1 -> 0xCC.U, 2 -> 0xBB.U, 3 -> 0xAA.U)
+ chisel3.assert(insideVecLit(0) === 0xDD.U)
+ chisel3.assert(insideVecLit(1) === 0xCC.U)
+ chisel3.assert(insideVecLit(2) === 0xBB.U)
+ chisel3.assert(insideVecLit(3) === 0xAA.U)
+
+ chisel3.assert(insideVecLit(0) === outsideVecLit(0))
+ chisel3.assert(insideVecLit(1) === outsideVecLit(1))
+ chisel3.assert(insideVecLit(2) === outsideVecLit(2))
+ chisel3.assert(insideVecLit(3) === outsideVecLit(3))
+
+ val vecWire1 = Wire(Vec(4, UInt(16.W)))
+ vecWire1 := outsideVecLit
+
+ chisel3.assert(vecWire1(0) === 0xDD.U)
+ chisel3.assert(vecWire1(1) === 0xCC.U)
+ chisel3.assert(vecWire1(2) === 0xBB.U)
+ chisel3.assert(vecWire1(3) === 0xAA.U)
+
+ val vecWire2 = Wire(Vec(4, UInt(16.W)))
+ vecWire2 := insideVecLit
+
+ chisel3.assert(vecWire2(0) === 0xDD.U)
+ chisel3.assert(vecWire2(1) === 0xCC.U)
+ chisel3.assert(vecWire2(2) === 0xBB.U)
+ chisel3.assert(vecWire2(3) === 0xAA.U)
+
+ stop()
+ }
+ }
+ }
+
+ "partial vec literals should work in RTL" in {
+ assertTesterPasses{ new BasicTester{
+ val vecLit = Vec(4, UInt(8.W)).Lit(0 -> 42.U, 2 -> 5.U)
+ chisel3.assert(vecLit(0) === 42.U)
+ chisel3.assert(vecLit(2) === 5.U)
+
+ val vecWire = Wire(Vec(4, UInt(8.W)))
+ vecWire := vecLit
+
+ chisel3.assert(vecWire(0) === 42.U)
+ chisel3.assert(vecWire(2) === 5.U)
+
+ stop()
+ }}
+ }
+
+ "nested vec literals should be constructable" in {
+ val outerVec = Vec(2, Vec(3, UInt(4.W))).Lit(
+ 0 -> Vec(3, UInt(4.W)).Lit(0 -> 1.U, 1 -> 2.U, 2 -> 3.U),
+ 1 -> Vec(3, UInt(4.W)).Lit(0 -> 4.U, 1 -> 5.U, 2 -> 6.U)
+ )
+
+ outerVec.litValue() should be (BigInt("654321", 16))
+ outerVec(0).litValue() should be (BigInt("321", 16))
+ outerVec(1).litValue() should be (BigInt("654", 16))
+ outerVec(0)(0).litValue() should be (BigInt(1))
+ outerVec(0)(1).litValue() should be (BigInt(2))
+ outerVec(0)(2).litValue() should be (BigInt(3))
+ outerVec(1)(0).litValue() should be (BigInt(4))
+ outerVec(1)(1).litValue() should be (BigInt(5))
+ outerVec(1)(2).litValue() should be (BigInt(6))
+ }
+
+ "contained vecs should work" in {
+ assertTesterPasses{ new BasicTester {
+ val outerVec = Vec(2, Vec(3, UInt(4.W))).Lit(
+ 0 -> Vec(3, UInt(4.W)).Lit(0 -> 1.U, 1 -> 2.U, 2 -> 3.U),
+ 1 -> Vec(3, UInt(4.W)).Lit(0 -> 4.U, 1 -> 5.U, 2 -> 6.U)
+ )
+
+ chisel3.assert(outerVec(0)(0) === 1.U)
+ chisel3.assert(outerVec(0)(1) === 2.U)
+ chisel3.assert(outerVec(0)(2) === 3.U)
+ chisel3.assert(outerVec(1)(0) === 4.U)
+ chisel3.assert(outerVec(1)(1) === 5.U)
+ chisel3.assert(outerVec(1)(2) === 6.U)
+
+ val v0 = outerVec(0)
+ val v1 = outerVec(1)
+ chisel3.assert(v0(0) === 1.U)
+ chisel3.assert(v0(1) === 2.U)
+ chisel3.assert(v0(2) === 3.U)
+ chisel3.assert(v1(0) === 4.U)
+ chisel3.assert(v1(1) === 5.U)
+ chisel3.assert(v1(2) === 6.U)
+
+ stop()
+ }}
+ }
+
+ //TODO: decide what behavior here should be
+ "This doesn't work should it" ignore {
+ assertTesterPasses {
+ new BasicTester {
+ def vecFactory = Vec(2, FixedPoint(8.W, 4.BP))
+
+ val vecWire1 = Wire(Output(vecFactory))
+ val vecLit1 = vecFactory.Lit(0 -> (1.5).F(8.W, 4.BP))
+ val vecLit2 = vecFactory.Lit(1 -> (3.25).F(8.W, 4.BP))
+
+ vecWire1 := vecLit1
+ vecWire1 := vecLit2
+ printf("vw1(0) %x vw1(1) %x\n", vecWire1(0).asUInt(), vecWire1(1).asUInt())
+ chisel3.assert(vecWire1(0) === (1.5).F(8.W, 4.BP))
+ chisel3.assert(vecWire1(1) === (3.25).F(8.W, 4.BP))
+ stop()
+ }
+ }
+ }
+
+ "partially initialized Vec literals should assign" in {
+ assertTesterPasses {
+ new BasicTester {
+ def vecFactory = Vec(2, FixedPoint(8.W, 4.BP))
+
+ val vecWire1 = Wire(Output(vecFactory))
+ val vecWire2 = Wire(Output(vecFactory))
+ val vecLit1 = vecFactory.Lit(0 -> (1.5).F(8.W, 4.BP))
+ val vecLit2 = vecFactory.Lit(1 -> (3.25).F(8.W, 4.BP))
+
+ vecWire1 := vecLit1
+ vecWire2 := vecLit2
+ vecWire1(1) := (0.5).F(8.W, 4.BP)
+ printf("vw1(0) %x vw1(1) %x\n", vecWire1(0).asUInt(), vecWire1(1).asUInt())
+ chisel3.assert(vecWire1(0) === (1.5).F(8.W, 4.BP))
+ chisel3.assert(vecWire1(1) === (0.5).F(8.W, 4.BP)) // Last connect won
+ chisel3.assert(vecWire2(1) === (3.25).F(8.W, 4.BP))
+ stop()
+ }
+ }
+ }
+
+ "Vec literals should work as register reset values" in {
+ assertTesterPasses {
+ new BasicTester {
+ val r = RegInit(Vec(3, UInt(11.W)).Lit(0 -> 0xA.U, 1 -> 0xB.U, 2 -> 0xC.U))
+ r := (r.asUInt + 1.U).asTypeOf(Vec(3, UInt(11.W))) // prevent constprop
+
+ // check reset values on first cycle out of reset
+ chisel3.assert(r(0) === 0xA.U)
+ chisel3.assert(r(1) === 0xB.U)
+ chisel3.assert(r(2) === 0xC.U)
+ stop()
+ }
+ }
+ }
+
+ "partially initialized Vec literals should work as register reset values" in {
+ assertTesterPasses {
+ new BasicTester {
+ val r = RegInit(Vec(3, UInt(11.W)).Lit(0 -> 0xA.U, 2 -> 0xC.U))
+ r := (r.asUInt + 1.U).asTypeOf(Vec(3, UInt(11.W))) // prevent constprop
+ // check reset values on first cycle out of reset
+ chisel3.assert(r(0) === 0xA.U)
+ chisel3.assert(r(2) === 0xC.U)
+ stop()
+ }
+ }
+ }
+
+ "Fields extracted from Vec Literals should work as register reset values" in {
+ assertTesterPasses {
+ new BasicTester {
+ val r = RegInit(Vec(3, UInt(11.W)).Lit(0 -> 0xA.U, 2 -> 0xC.U).apply(0))
+ r := r + 1.U // prevent const prop
+ chisel3.assert(r === 0xA.U) // coming out of reset
+ stop()
+ }
+ }
+ }
+
+ "DontCare fields extracted from Vec Literals should work as register reset values" in {
+ assertTesterPasses {
+ new BasicTester {
+ val r = RegInit(Vec(3, Bool()).Lit(0 -> true.B).apply(2))
+ r := reset.asBool
+ printf(p"r = $r\n") // Can't assert because reset value is DontCare
+ stop()
+ }
+ }
+ }
+
+ "DontCare fields extracted from Vec Literals should work in other Expressions" in {
+ assertTesterPasses {
+ new BasicTester {
+ val x = Vec(3, Bool()).Lit(0 -> true.B).apply(2) || true.B
+ chisel3.assert(x === true.B)
+ stop()
+ }
+ }
+ }
+
+ "vec literals with non-literal values should fail" in {
+ val exc = intercept[VecLiteralException] {
+ extractCause[VecLiteralException] {
+ ChiselStage.elaborate {
+ new RawModule {
+ (Vec(3, UInt(11.W)).Lit(0 -> UInt()))
+ }
+ }
+ }
+ }
+ exc.getMessage should include("field 0 specified with non-literal value UInt")
+ }
+
+ "vec literals are instantiated on connect" in {
+ class VecExample5 extends RawModule {
+ val out = IO(Output(Vec(2, UInt(4.W))))
+ val bundle = Vec(2, UInt(4.W)).Lit(
+ 0 -> 0xa.U,
+ 1 -> 0xb.U
+ )
+ out := bundle
+ }
+
+ val firrtl = (new chisel3.stage.ChiselStage).emitFirrtl(new VecExample5, args = Array("--full-stacktrace"))
+ firrtl should include("""out[0] <= UInt<4>("ha")""")
+ firrtl should include("""out[1] <= UInt<4>("hb")""")
+ }
+
+ class SubBundle extends Bundle {
+ val foo = UInt(8.W)
+ val bar = UInt(4.W)
+ }
+
+ class VecExample extends RawModule {
+ val out = IO(Output(Vec(2, new SubBundle)))
+ val bundle = Vec(2, new SubBundle).Lit(
+ 0 -> (new SubBundle).Lit(_.foo -> 42.U, _.bar -> 22.U),
+ 1 -> (new SubBundle).Lit(_.foo -> 7.U, _.bar -> 3.U)
+ )
+ out := bundle
+ }
+
+ "vec literals can contain bundles" in {
+ val chirrtl = (new chisel3.stage.ChiselStage).emitChirrtl(new VecExample, args = Array("--full-stacktrace"))
+ chirrtl should include("""out[0].bar <= UInt<5>("h016")""")
+ chirrtl should include("""out[0].foo <= UInt<6>("h02a")""")
+ chirrtl should include("""out[1].bar <= UInt<2>("h03")""")
+ chirrtl should include("""out[1].foo <= UInt<3>("h07")""")
+
+ }
+
+ "vec literals can have bundle children" in {
+ val vec = Vec(2, new SubBundle).Lit(
+ 0 -> (new SubBundle).Lit(_.foo -> 0xab.U, _.bar -> 0xc.U),
+ 1 -> (new SubBundle).Lit(_.foo -> 0xde.U, _.bar -> 0xf.U)
+ )
+ vec.litValue().toString(16) should be("defabc")
+ }
+
+ "vec literals can have bundle children assembled incrementally" in {
+ val bundle1 = (new SubBundle).Lit(_.foo -> 0xab.U, _.bar -> 0xc.U)
+ val bundle2 = (new SubBundle).Lit(_.foo -> 0xde.U, _.bar -> 0xf.U)
+
+ bundle1.litValue().toString(16) should be("abc")
+ bundle2.litValue().toString(16) should be("def")
+
+ val vec = Vec(2, new SubBundle).Lit(0 -> bundle1, 1 -> bundle2)
+
+ vec.litValue().toString(16) should be("defabc")
+ }
+
+ "bundles can contain vec lits" in {
+ val vec1 = Vec(3, UInt(4.W)).Lit(0 -> 0xa.U, 1 -> 0xb.U, 2 -> 0xc.U)
+ val vec2 = Vec(2, UInt(4.W)).Lit(0 -> 0xd.U, 1 -> 0xe.U)
+ val bundle = (new Bundle {
+ val foo = Vec(3, UInt(4.W))
+ val bar = Vec(2, UInt(4.W))
+ }).Lit(_.foo -> vec1, _.bar -> vec2)
+ bundle.litValue().toString(16) should be("cbaed")
+ }
+
+ "bundles can contain vec lits in-line" in {
+ val bundle = (new Bundle {
+ val foo = Vec(3, UInt(4.W))
+ val bar = Vec(2, UInt(4.W))
+ }).Lit(
+ _.foo -> Vec(3, UInt(4.W)).Lit(0 -> 0xa.U, 1 -> 0xb.U, 2 -> 0xc.U),
+ _.bar -> Vec(2, UInt(4.W)).Lit(0 -> 0xd.U, 1 -> 0xe.U)
+ )
+ bundle.litValue().toString(16) should be("cbaed")
+ }
+
+ "Vec.Lit is a trivial Vec literal factory" in {
+ val vec = Vec.Lit(0xa.U, 0xb.U)
+ vec(0).litValue() should be(0xa)
+ vec(1).litValue() should be(0xb)
+ }
+
+ "Vec.Lit bases it's element width on the widest literal supplied" in {
+ val vec = Vec.Lit(0xa.U, 0xbbbb.U)
+ vec(0).litValue() should be(0xa)
+ vec(1).litValue() should be(0xbbbb)
+ vec.length should be(2)
+ vec.getWidth should be(16 * 2)
+ vec.litValue() should be(BigInt("bbbb000a", 16))
+ }
+}