Skip to content

Commit ce05462

Browse files
authored
Support literals in DataView (chipsalliance#3964)
1 parent 5cd8ad0 commit ce05462

File tree

4 files changed

+92
-10
lines changed

4 files changed

+92
-10
lines changed

core/src/main/scala/chisel3/Aggregate.scala

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
package chisel3
44

55
import chisel3.experimental.VecLiterals.AddVecLiteralConstructor
6-
import chisel3.experimental.dataview.{isView, reifySingleData, InvalidViewException}
6+
import chisel3.experimental.dataview.{isView, reify, reifySingleData, InvalidViewException}
77

88
import scala.collection.immutable.{SeqMap, VectorMap}
99
import scala.collection.mutable.{HashSet, LinkedHashMap}
@@ -29,7 +29,7 @@ sealed abstract class Aggregate extends Data {
2929

3030
private def checkingLitOption(checkForDontCares: Boolean): Option[BigInt] = {
3131
// Shift the accumulated value by our width and add in our component, masked by our width.
32-
def shiftAdd(accumulator: Option[BigInt], elt: Data): Option[BigInt] = {
32+
def shiftAdd(elt: Data, accumulator: Option[BigInt]): Option[BigInt] = {
3333
(accumulator, elt.litOption) match {
3434
case (Some(accumulator), Some(eltLit)) =>
3535
val width = elt.width.get
@@ -44,24 +44,32 @@ sealed abstract class Aggregate extends Data {
4444
}
4545

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

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

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

6775
/** Returns a Seq of the immediate contents of this Aggregate, in order.

core/src/main/scala/chisel3/Element.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package chisel3
55
import chisel3.internal.Builder.pushCommand
66
import chisel3.internal.firrtl.ir._
77
import chisel3.experimental.SourceInfo
8+
import chisel3.experimental.dataview.reify
89
import chisel3.internal._
910

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

5253
private[chisel3] def litArgOption: Option[LitArg] = topBindingOpt match {
5354
case Some(ElementLitBinding(litArg)) => Some(litArg)
54-
case _ => None
55+
case Some(_: ViewBinding) =>
56+
reify(this).litArgOption
57+
case _ => None
5558
}
5659

5760
override def litOption: Option[BigInt] = litArgOption.map(_.num)

core/src/main/scala/chisel3/internal/Builder.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -940,7 +940,7 @@ private[chisel3] object Builder extends LazyLogging {
940940
val localTarget = view.toTarget
941941
val absTarget = view.toAbsoluteTarget
942942
val elts = getRecursiveFields.lazily(view, "").collect { case (elt: Element, _) => elt }
943-
for (elt <- elts) {
943+
for (elt <- elts if !elt.isLit) {
944944
// This is a hack to not crash when .viewAs is called on non-hardware
945945
// It can be removed in Chisel 6.0.0 when it becomes illegal to call .viewAs on non-hardware
946946
val targetOfViewOpt =

src/test/scala/chiselTests/experimental/DataView.scala

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,6 +1050,77 @@ class DataViewSpec extends ChiselFlatSpec {
10501050
)
10511051
}
10521052

1053+
it should "preserve literal values for Elements" in {
1054+
class MyModule extends Module {
1055+
val x = 123.U
1056+
val xv = x.viewAs[UInt]
1057+
xv.litOption should be(x.litOption)
1058+
xv.litValue should be(x.litValue)
1059+
val y = -23.S
1060+
val yv = y.viewAs[SInt]
1061+
yv.litOption should be(y.litOption)
1062+
yv.litValue should be(y.litValue)
1063+
}
1064+
ChiselStage.emitCHIRRTL(new MyModule)
1065+
}
1066+
1067+
it should "preserve literal values for BundleLiterals" in {
1068+
import chisel3.experimental.BundleLiterals._
1069+
class BundleA extends Bundle {
1070+
val foo = UInt(4.W)
1071+
val bar = UInt(4.W)
1072+
}
1073+
class BundleB extends Bundle {
1074+
val a = UInt(4.W)
1075+
val b = UInt(4.W)
1076+
val c = UInt(4.W)
1077+
}
1078+
implicit val dv =
1079+
DataView[BundleA, BundleB](_ => new BundleB, _.foo -> _.c, _.bar -> _.a, (_, b) => 6.U(4.W) -> b.b)
1080+
class MyModule extends Module {
1081+
val bunA = (new BundleA).Lit(_.foo -> 0xa.U, _.bar -> 0xd.U)
1082+
val bunAView = bunA.viewAs[BundleA]
1083+
bunA.litValue should be(0xad)
1084+
bunA.litOption should be(Some(0xad))
1085+
bunAView.litValue should be(0xad)
1086+
bunAView.litOption should be(Some(0xad))
1087+
1088+
val bunBView = bunA.viewAs[BundleB]
1089+
bunBView.litValue should be(0xd6a)
1090+
bunBView.litOption should be(Some(0xd6a))
1091+
}
1092+
ChiselStage.emitCHIRRTL(new MyModule)
1093+
}
1094+
1095+
it should "preserve literal values for VecLiterals (viewed as nested Bundles)" in {
1096+
import chisel3.experimental.VecLiterals._
1097+
case class Box(value: UInt) extends Bundle
1098+
class MyBundle extends Bundle {
1099+
val foo = Vec(2, UInt(4.W))
1100+
val bar = Vec(2, Box(UInt(4.W)))
1101+
}
1102+
implicit val dv = DataView[Vec[UInt], MyBundle](
1103+
_ => new MyBundle,
1104+
_(0) -> _.foo(0),
1105+
_(1) -> _.bar(1).value,
1106+
_(2) -> _.bar(0).value,
1107+
_(3) -> _.foo(1)
1108+
)
1109+
class MyModule extends Module {
1110+
val vec = Vec.Lit(0xa.U, 0xb.U, 0xc.U, 0xd.U)
1111+
val vecView = vec.viewAs[Vec[UInt]]
1112+
vec.litValue should be(0xdcba)
1113+
vec.litOption should be(Some(0xdcba))
1114+
vecView.litValue should be(0xdcba)
1115+
vecView.litOption should be(Some(0xdcba))
1116+
1117+
val bunView = vec.viewAs[MyBundle]
1118+
bunView.litValue should be(0xdabc)
1119+
bunView.litOption should be(Some(0xdabc))
1120+
}
1121+
ChiselStage.emitCHIRRTL(new MyModule)
1122+
}
1123+
10531124
behavior.of("PartialDataView")
10541125

10551126
it should "still error if the mapping is non-total in the view" in {

0 commit comments

Comments
 (0)