summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorducky2015-12-10 12:14:53 -0800
committerducky2015-12-10 12:14:53 -0800
commitf74180a50bf466d275e1faeb78ccf67b51387bcb (patch)
treeedd986e56e9783002b881ad6eedc0fc5eed73bdf /src
parent035a30d25cdd955af6385c1334826781b17d894c (diff)
Add Option support in Bundle
Diffstat (limited to 'src')
-rw-r--r--src/main/scala/Chisel/Aggregate.scala34
-rw-r--r--src/test/scala/chiselTests/OptionBundle.scala62
2 files changed, 90 insertions, 6 deletions
diff --git a/src/main/scala/Chisel/Aggregate.scala b/src/main/scala/Chisel/Aggregate.scala
index 1506833c..35b8b4e5 100644
--- a/src/main/scala/Chisel/Aggregate.scala
+++ b/src/main/scala/Chisel/Aggregate.scala
@@ -254,28 +254,50 @@ class Bundle extends Aggregate(NO_DIR) {
lazy val elements: ListMap[String, Data] = ListMap(namedElts:_*)
/** Returns a best guess at whether a field in this Bundle is a user-defined
- * Bundle element.
+ * Bundle element without looking at type signatures.
*/
private def isBundleField(m: java.lang.reflect.Method) =
m.getParameterTypes.isEmpty &&
!java.lang.reflect.Modifier.isStatic(m.getModifiers) &&
- classOf[Data].isAssignableFrom(m.getReturnType) &&
!(Bundle.keywords contains m.getName) && !(m.getName contains '$')
+ /** Returns a field's contained user-defined Bundle element if it appears to
+ * be one, otherwise returns None.
+ */
+ private def getBundleField(m: java.lang.reflect.Method): Option[Data] = {
+ if (isBundleField(m) &&
+ (classOf[Data].isAssignableFrom(m.getReturnType) ||
+ classOf[Option[_]].isAssignableFrom(m.getReturnType))) {
+ m.invoke(this) match {
+ case d: Data =>
+ Some(d)
+ case o: Option[_] =>
+ o.getOrElse(None) match {
+ case d: Data =>
+ Some(d)
+ case _ => None
+ }
+ case _ => None
+ }
+ } else {
+ None
+ }
+ }
+
/** Returns a list of elements in this Bundle.
*/
private[Chisel] lazy val namedElts = {
val nameMap = LinkedHashMap[String, Data]()
val seen = HashSet[Data]()
- for (m <- getClass.getMethods.sortWith(_.getName < _.getName); if isBundleField(m)) {
- m.invoke(this) match {
- case d: Data =>
+ for (m <- getClass.getMethods.sortWith(_.getName < _.getName)) {
+ getBundleField(m) match {
+ case Some(d) =>
if (nameMap contains m.getName) {
require(nameMap(m.getName) eq d)
} else if (!seen(d)) {
nameMap(m.getName) = d; seen += d
}
- case _ =>
+ case None =>
}
}
ArrayBuffer(nameMap.toSeq:_*) sortWith {case ((an, a), (bn, b)) => (a._id > b._id) || ((a eq b) && (an > bn))}
diff --git a/src/test/scala/chiselTests/OptionBundle.scala b/src/test/scala/chiselTests/OptionBundle.scala
new file mode 100644
index 00000000..1b7be1ec
--- /dev/null
+++ b/src/test/scala/chiselTests/OptionBundle.scala
@@ -0,0 +1,62 @@
+// See LICENSE for license details.
+
+package chiselTests
+
+import org.scalatest._
+import Chisel._
+import Chisel.testers.BasicTester
+
+class OptionBundle(hasIn: Boolean) extends Bundle {
+ val in = if (hasIn) {
+ Some(Bool(INPUT))
+ } else {
+ None
+ }
+ val out = Bool(OUTPUT)
+}
+
+class OptionBundleModule(hasIn: Boolean) extends Module {
+ val io = new OptionBundle(hasIn)
+ if (hasIn) {
+ io.out := io.in.get
+ } else {
+ io.out := Bool(false)
+ }
+}
+
+class SomeOptionBundleTester(expected: Boolean) extends BasicTester {
+ val mod = Module(new OptionBundleModule(true))
+ mod.io.in.get := Bool(expected)
+ io.error := mod.io.out != Bool(expected)
+ io.done := Bool(true)
+}
+
+class NoneOptionBundleTester() extends BasicTester {
+ val mod = Module(new OptionBundleModule(true))
+ io.error := mod.io.out != Bool(false)
+ io.done := Bool(true)
+}
+
+class InvalidOptionBundleTester() extends BasicTester {
+ val mod = Module(new OptionBundleModule(false))
+ mod.io.in.get := Bool(true)
+ io.error := UInt(1)
+ io.done := Bool(true)
+}
+
+class OptionBundleSpec extends ChiselFlatSpec {
+ "A Bundle with an Option field" should "work properly if the Option field is not None" in {
+ assert(execute { new SomeOptionBundleTester(true) })
+ assert(execute { new SomeOptionBundleTester(false) })
+ }
+
+ "A Bundle with an Option field" should "compile if the Option field is None" in {
+ assert(execute { new NoneOptionBundleTester() })
+ }
+
+ "A Bundle with an Option field" should "assert out accessing a None Option field" in {
+ a [Exception] should be thrownBy {
+ elaborate { new InvalidOptionBundleTester() }
+ }
+ }
+}