Skip to content
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

Support literals in DataView (backport #3964) #3965

Merged
merged 2 commits into from
Apr 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 16 additions & 8 deletions core/src/main/scala/chisel3/Aggregate.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
package chisel3

import chisel3.experimental.VecLiterals.AddVecLiteralConstructor
import chisel3.experimental.dataview.{isView, reifySingleData, InvalidViewException}
import chisel3.experimental.dataview.{isView, reify, reifySingleData, InvalidViewException}

import scala.collection.immutable.{SeqMap, VectorMap}
import scala.collection.mutable.{HashSet, LinkedHashMap}
Expand All @@ -27,7 +27,7 @@ sealed abstract class Aggregate extends Data {

private def checkingLitOption(checkForDontCares: Boolean): 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] = {
def shiftAdd(elt: Data, accumulator: Option[BigInt]): Option[BigInt] = {
(accumulator, elt.litOption) match {
case (Some(accumulator), Some(eltLit)) =>
val width = elt.width.get
Expand All @@ -42,24 +42,32 @@ sealed abstract class Aggregate extends Data {
}

topBindingOpt match {
case Some(BundleLitBinding(_)) | Some(VecLitBinding(_)) =>
getElements.reverse
.foldLeft[Option[BigInt]](Some(BigInt(0)))(shiftAdd)
case Some(_: BundleLitBinding | _: VecLitBinding | _: AggregateViewBinding) =>
// Records store elements in reverse order and higher indices are more significant in Vecs
this.getElements.foldRight(Option(BigInt(0)))(shiftAdd)
case _ => None
}
}

/** Return an Aggregate's literal value if it is a literal, None otherwise.
* If any element of the aggregate is not a literal with a defined width, the result isn't a literal.
* If any element of the aggregate is not a literal (or DontCare), the result isn't a literal.
*
* @return an Aggregate's literal value if it is a literal.
* @note [[DontCare]] is allowed and will be replaced with 0. Use [[litValue]] to disallow DontCare.
* @return an Aggregate's literal value if it is a literal, None otherwise.
*/
override def litOption: Option[BigInt] = {
checkingLitOption(checkForDontCares = false)
}

/** Return an Aggregate's literal value if it is a literal, otherwise an exception is thrown.
* If any element of the aggregate is not a literal with a defined width, the result isn't a literal.
*
* @return an Aggregate's literal value if it is a literal, exception otherwise.
*/
override def litValue: BigInt = {
checkingLitOption(checkForDontCares = true).get
checkingLitOption(checkForDontCares = true).getOrElse(
throw new chisel3.ChiselException(s"Cannot ask for litValue of $this as it is not a literal.")
)
}

/** Returns a Seq of the immediate contents of this Aggregate, in order.
Expand Down
5 changes: 4 additions & 1 deletion core/src/main/scala/chisel3/Element.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package chisel3
import chisel3.internal.Builder.pushCommand
import chisel3.internal.firrtl._
import chisel3.experimental.SourceInfo
import chisel3.experimental.dataview.reify
import chisel3.internal._

/** Element is a leaf data type: it cannot contain other [[Data]] objects. Example uses are for representing primitive
Expand Down Expand Up @@ -51,7 +52,9 @@ abstract class Element extends Data {

private[chisel3] def litArgOption: Option[LitArg] = topBindingOpt match {
case Some(ElementLitBinding(litArg)) => Some(litArg)
case _ => None
case Some(_: ViewBinding) =>
reify(this).litArgOption
case _ => None
}

override def litOption: Option[BigInt] = litArgOption.map(_.num)
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/scala/chisel3/internal/Builder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -827,7 +827,7 @@ private[chisel3] object Builder extends LazyLogging {
// It can be removed in Chisel 6.0.0 when it becomes illegal to call .viewAs on non-hardware
val targetOfViewOpt =
try {
Some(reify(elt))
Some(reify(elt)).filterNot(_.isLit)
} catch {
case _: NoSuchElementException => None
}
Expand Down
71 changes: 71 additions & 0 deletions src/test/scala/chiselTests/experimental/DataView.scala
Original file line number Diff line number Diff line change
Expand Up @@ -928,6 +928,77 @@ class DataViewSpec extends ChiselFlatSpec {
e.getMessage should include("View mapping must only contain Elements within the View")
}

it should "preserve literal values for Elements" in {
class MyModule extends Module {
val x = 123.U
val xv = x.viewAs[UInt]
xv.litOption should be(x.litOption)
xv.litValue should be(x.litValue)
val y = -23.S
val yv = y.viewAs[SInt]
yv.litOption should be(y.litOption)
yv.litValue should be(y.litValue)
}
ChiselStage.emitCHIRRTL(new MyModule)
}

it should "preserve literal values for BundleLiterals" in {
import chisel3.experimental.BundleLiterals._
class BundleA extends Bundle {
val foo = UInt(4.W)
val bar = UInt(4.W)
}
class BundleB extends Bundle {
val a = UInt(4.W)
val b = UInt(4.W)
val c = UInt(4.W)
}
implicit val dv =
DataView[BundleA, BundleB](_ => new BundleB, _.foo -> _.c, _.bar -> _.a, (_, b) => 6.U(4.W) -> b.b)
class MyModule extends Module {
val bunA = (new BundleA).Lit(_.foo -> 0xa.U, _.bar -> 0xd.U)
val bunAView = bunA.viewAs[BundleA]
bunA.litValue should be(0xad)
bunA.litOption should be(Some(0xad))
bunAView.litValue should be(0xad)
bunAView.litOption should be(Some(0xad))

val bunBView = bunA.viewAs[BundleB]
bunBView.litValue should be(0xd6a)
bunBView.litOption should be(Some(0xd6a))
}
ChiselStage.emitCHIRRTL(new MyModule)
}

it should "preserve literal values for VecLiterals (viewed as nested Bundles)" in {
import chisel3.experimental.VecLiterals._
case class Box(value: UInt) extends Bundle
class MyBundle extends Bundle {
val foo = Vec(2, UInt(4.W))
val bar = Vec(2, Box(UInt(4.W)))
}
implicit val dv = DataView[Vec[UInt], MyBundle](
_ => new MyBundle,
_(0) -> _.foo(0),
_(1) -> _.bar(1).value,
_(2) -> _.bar(0).value,
_(3) -> _.foo(1)
)
class MyModule extends Module {
val vec = Vec.Lit(0xa.U, 0xb.U, 0xc.U, 0xd.U)
val vecView = vec.viewAs[Vec[UInt]]
vec.litValue should be(0xdcba)
vec.litOption should be(Some(0xdcba))
vecView.litValue should be(0xdcba)
vecView.litOption should be(Some(0xdcba))

val bunView = vec.viewAs[MyBundle]
bunView.litValue should be(0xdabc)
bunView.litOption should be(Some(0xdabc))
}
ChiselStage.emitCHIRRTL(new MyModule)
}

behavior.of("PartialDataView")

it should "still error if the mapping is non-total in the view" in {
Expand Down
Loading