summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala5
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/Binding.scala4
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/Bits.scala2
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/Data.scala17
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/RawModule.scala14
-rw-r--r--chiselFrontend/src/main/scala/chisel3/core/StrongEnum.scala2
-rw-r--r--src/test/scala/chiselTests/AnalogSpec.scala55
7 files changed, 75 insertions, 24 deletions
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala
index c75974f0..7e3920eb 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/Aggregate.scala
@@ -136,7 +136,8 @@ object Vec extends VecFactory
sealed class Vec[T <: Data] private[core] (gen: => T, val length: Int)
extends Aggregate with VecLike[T] {
override def toString: String = {
- s"$sample_element[$length]$bindingToString"
+ val elementType = sample_element.cloneType
+ s"$elementType[$length]$bindingToString"
}
private[core] override def typeEquivalent(that: Data): Boolean = that match {
@@ -155,8 +156,6 @@ sealed class Vec[T <: Data] private[core] (gen: => T, val length: Int)
child.bind(ChildBinding(this), resolvedDirection)
}
- // Note: this differs from the Aggregate.bind behavior on an empty Vec, since this looks at the
- // sample element instead of actual elements.
direction = sample_element.direction
}
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Binding.scala b/chiselFrontend/src/main/scala/chisel3/core/Binding.scala
index 37ce3f66..e30b91ec 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/Binding.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/Binding.scala
@@ -30,7 +30,7 @@ object requireIsHardware {
case Some(x: BaseModule) => x._compatAutoWrapPorts
case _ =>
}
- if (!node.topBindingOpt.isDefined) {
+ if (!node.isSynthesizable) {
val prefix = if (msg.nonEmpty) s"$msg " else ""
throw Binding.ExpectedHardwareException(s"$prefix'$node' must be hardware, " +
"not a bare Chisel type. Perhaps you forgot to wrap it in Wire(_) or IO(_)?")
@@ -41,7 +41,7 @@ object requireIsHardware {
/** Requires that a node is a chisel type (not hardware, "unbound")
*/
object requireIsChiselType {
- def apply(node: Data, msg: String = ""): Unit = if (node.topBindingOpt.isDefined) {
+ def apply(node: Data, msg: String = ""): Unit = if (node.isSynthesizable) {
val prefix = if (msg.nonEmpty) s"$msg " else ""
throw Binding.ExpectedChiselTypeException(s"$prefix'$node' must be a Chisel type, not hardware")
}
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala
index e35d12f0..424db5cb 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/Bits.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/Bits.scala
@@ -1776,6 +1776,8 @@ final class Analog private (private[chisel3] val width: Width) extends Element {
val targetTopBinding = target match {
case target: TopBinding => target
case ChildBinding(parent) => parent.topBinding
+ // See https://github.com/freechipsproject/chisel3/pull/946
+ case SampleElementBinding(parent) => parent.topBinding
}
// Analog counts as different directions based on binding context
diff --git a/chiselFrontend/src/main/scala/chisel3/core/Data.scala b/chiselFrontend/src/main/scala/chisel3/core/Data.scala
index abb5675c..7ff58b54 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/Data.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/Data.scala
@@ -146,7 +146,7 @@ object DataMirror {
// Internal reflection-style APIs, subject to change and removal whenever.
object internal { // scalastyle:ignore object.name
- def isSynthesizable(target: Data): Boolean = target.topBindingOpt.isDefined
+ def isSynthesizable(target: Data): Boolean = target.isSynthesizable
// For those odd cases where you need to care about object reference and uniqueness
def chiselTypeClone[T<:Data](target: Data): T = {
target.cloneTypeFull.asInstanceOf[T]
@@ -314,14 +314,18 @@ abstract class Data extends HasId with NamedComponent with SourceInfoDoc { // sc
_binding = Some(target)
}
+ // Similar to topBindingOpt except it explicitly excludes SampleElements which are bound but not
+ // hardware
+ private[core] final def isSynthesizable: Boolean = _binding.map {
+ case ChildBinding(parent) => parent.isSynthesizable
+ case _: TopBinding => true
+ case _: SampleElementBinding[_] => false
+ }.getOrElse(false)
+
private[core] def topBindingOpt: Option[TopBinding] = _binding.flatMap {
case ChildBinding(parent) => parent.topBindingOpt
case bindingVal: TopBinding => Some(bindingVal)
- case _: SampleElementBinding[_] => None
- // TODO: technically, it's bound, but it's more of a ghost binding and None is probably the most appropriate
- // Note: sample elements should not be user-accessible, so there's not really a good reason to access its
- // top binding. However, we can't make this assert out right not because a larger refactoring is needed.
- // See https://github.com/freechipsproject/chisel3/pull/946
+ case SampleElementBinding(parent) => parent.topBindingOpt
}
private[core] def topBinding: TopBinding = topBindingOpt.get
@@ -351,6 +355,7 @@ abstract class Data extends HasId with NamedComponent with SourceInfoDoc { // sc
// User-friendly representation of the binding as a helper function for toString.
// Provides a unhelpful fallback for literals, which should have custom rendering per
// Data-subtype.
+ // TODO Is this okay for sample_element? It *shouldn't* be visible to users
protected def bindingToString: String = topBindingOpt match {
case None => ""
case Some(OpBinding(enclosure)) => s"(OpResult in ${enclosure.desiredName})"
diff --git a/chiselFrontend/src/main/scala/chisel3/core/RawModule.scala b/chiselFrontend/src/main/scala/chisel3/core/RawModule.scala
index b1cae1b7..397debcb 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/RawModule.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/RawModule.scala
@@ -75,12 +75,14 @@ abstract class RawModule(implicit moduleCompileOptions: CompileOptions)
id match {
case id: BaseModule => id.forceName(default=id.desiredName, _namespace)
case id: MemBase[_] => id.forceName(default="_T", _namespace)
- case id: Data if id.topBindingOpt.isDefined => id.topBinding match {
- case OpBinding(_) | MemoryPortBinding(_) | PortBinding(_) | RegBinding(_) | WireBinding(_) =>
- id.forceName(default="_T", _namespace)
- case _ => // don't name literals
- }
- case id: Data if id.topBindingOpt.isEmpty => // don't name unbound types
+ case id: Data =>
+ if (id.isSynthesizable) {
+ id.topBinding match {
+ case OpBinding(_) | MemoryPortBinding(_) | PortBinding(_) | RegBinding(_) | WireBinding(_) =>
+ id.forceName(default="_T", _namespace)
+ case _ => // don't name literals
+ }
+ } // else, don't name unbound types
}
id._onModuleClose
}
diff --git a/chiselFrontend/src/main/scala/chisel3/core/StrongEnum.scala b/chiselFrontend/src/main/scala/chisel3/core/StrongEnum.scala
index 1689e6ad..63f7a8a0 100644
--- a/chiselFrontend/src/main/scala/chisel3/core/StrongEnum.scala
+++ b/chiselFrontend/src/main/scala/chisel3/core/StrongEnum.scala
@@ -161,7 +161,7 @@ abstract class EnumType(private val factory: EnumFactory, selfAnnotating: Boolea
super.bind(target, parentDirection)
// Make sure we only annotate hardware and not literals
- if (selfAnnotating && topBindingOpt.isDefined && topBindingOpt.get.isInstanceOf[ConstrainedBinding]) {
+ if (selfAnnotating && isSynthesizable && topBindingOpt.get.isInstanceOf[ConstrainedBinding]) {
annotateEnum()
}
}
diff --git a/src/test/scala/chiselTests/AnalogSpec.scala b/src/test/scala/chiselTests/AnalogSpec.scala
index c5e9ed02..b262074c 100644
--- a/src/test/scala/chiselTests/AnalogSpec.scala
+++ b/src/test/scala/chiselTests/AnalogSpec.scala
@@ -5,7 +5,7 @@ package chiselTests
import chisel3._
import chisel3.util._
import chisel3.testers.BasicTester
-import chisel3.experimental.{Analog, attach, BaseModule}
+import chisel3.experimental.{Analog, attach, BaseModule, RawModule}
// IO for Modules that just connect bus to out
class AnalogReaderIO extends Bundle {
@@ -19,13 +19,20 @@ class AnalogWriterIO extends Bundle {
}
trait AnalogReader {
- self: BaseModule =>
- final val io = self.IO(new AnalogReaderIO)
+ def out: UInt
+ def bus: Analog
}
-class AnalogReaderBlackBox extends BlackBox with AnalogReader
+class AnalogReaderBlackBox extends BlackBox with AnalogReader {
+ val io = IO(new AnalogReaderIO)
+ def out = io.out
+ def bus = io.bus
+}
class AnalogReaderWrapper extends Module with AnalogReader {
+ val io = IO(new AnalogReaderIO)
+ def out = io.out
+ def bus = io.bus
val mod = Module(new AnalogReaderBlackBox)
io <> mod.io
}
@@ -41,6 +48,26 @@ class AnalogConnector extends Module {
io.bus1 <> io.bus2
}
+class VecAnalogReaderWrapper extends RawModule with AnalogReader {
+ val vecbus = IO(Vec(1, Analog(32.W)))
+ val out = IO(Output(UInt(32.W)))
+ val mod = Module(new AnalogReaderBlackBox)
+ def bus = vecbus(0)
+ mod.io.bus <> bus
+ out := mod.io.out
+}
+
+class VecBundleAnalogReaderWrapper extends RawModule with AnalogReader {
+ val vecBunBus = IO(Vec(1, new Bundle {
+ val analog = Analog(32.W)
+ }))
+ def bus = vecBunBus(0).analog
+ val out = IO(Output(UInt(32.W)))
+ val mod = Module(new AnalogReaderBlackBox)
+ mod.io.bus <> bus
+ out := mod.io.out
+}
+
// Parent class for tests connecing up AnalogReaders and AnalogWriters
abstract class AnalogTester extends BasicTester {
final val BusValue = "hdeadbeef".U
@@ -52,7 +79,7 @@ abstract class AnalogTester extends BasicTester {
writer.io.in := BusValue
final def check(reader: BaseModule with AnalogReader): Unit =
- assert(reader.io.out === BusValue)
+ assert(reader.out === BusValue)
}
class AnalogSpec extends ChiselFlatSpec {
@@ -180,7 +207,7 @@ class AnalogSpec extends ChiselFlatSpec {
assertTesterPasses(new AnalogTester {
val mods = Seq(Module(new AnalogReaderBlackBox), Module(new AnalogReaderWrapper))
val busWire = Wire(writer.io.bus.cloneType)
- attach(writer.io.bus, mods(0).io.bus, mods(1).io.bus)
+ attach(writer.io.bus, mods(0).bus, mods(1).bus)
mods.foreach(check(_))
}, Seq("/chisel3/AnalogBlackBox.v"))
}
@@ -207,5 +234,21 @@ class AnalogSpec extends ChiselFlatSpec {
}, Seq("/chisel3/AnalogBlackBox.v"))
}
}
+
+ it should "work with Vecs of Analog" in {
+ assertTesterPasses(new AnalogTester {
+ val mod = Module(new VecAnalogReaderWrapper)
+ mod.bus <> writer.io.bus
+ check(mod)
+ }, Seq("/chisel3/AnalogBlackBox.v"))
+ }
+
+ it should "work with Vecs of Bundles of Analog" in {
+ assertTesterPasses(new AnalogTester {
+ val mod = Module(new VecBundleAnalogReaderWrapper)
+ mod.bus <> writer.io.bus
+ check(mod)
+ }, Seq("/chisel3/AnalogBlackBox.v"))
+ }
}