summaryrefslogtreecommitdiff
path: root/core/src/main
diff options
context:
space:
mode:
authorJack2023-01-08 04:47:27 +0000
committerJack2023-01-08 04:47:27 +0000
commit5aa60ecda6bd2b02dfc7253a47e53c7647981a5c (patch)
tree53ea2570c4af7824d6203e0c0cd7953c1ba4910c /core/src/main
parenta50a5a287a23ba6b833b13d8cec84dd5dfe0fc61 (diff)
parent116210ff806ccdda91b4c3343f78bad66783d0e6 (diff)
Merge branch '3.5.x' into 3.5-release
Diffstat (limited to 'core/src/main')
-rw-r--r--core/src/main/scala/chisel3/Data.scala9
-rw-r--r--core/src/main/scala/chisel3/IO.scala41
-rw-r--r--core/src/main/scala/chisel3/Module.scala38
-rw-r--r--core/src/main/scala/chisel3/SeqUtils.scala5
-rw-r--r--core/src/main/scala/chisel3/experimental/package.scala2
-rw-r--r--core/src/main/scala/chisel3/internal/Builder.scala63
6 files changed, 111 insertions, 47 deletions
diff --git a/core/src/main/scala/chisel3/Data.scala b/core/src/main/scala/chisel3/Data.scala
index 50093333..dddc0d5d 100644
--- a/core/src/main/scala/chisel3/Data.scala
+++ b/core/src/main/scala/chisel3/Data.scala
@@ -256,8 +256,13 @@ package experimental {
def fullModulePorts(target: BaseModule): Seq[(String, Data)] = {
def getPortNames(name: String, data: Data): Seq[(String, Data)] = Seq(name -> data) ++ (data match {
case _: Element => Seq()
- case r: Record => r.elements.toSeq.flatMap { case (eltName, elt) => getPortNames(s"${name}_${eltName}", elt) }
- case v: Vec[_] => v.zipWithIndex.flatMap { case (elt, index) => getPortNames(s"${name}_${index}", elt) }
+ case r: Record =>
+ r.elements.toSeq.flatMap {
+ case (eltName, elt) =>
+ if (r._isOpaqueType) { getPortNames(s"${name}", elt) }
+ else { getPortNames(s"${name}_${eltName}", elt) }
+ }
+ case v: Vec[_] => v.zipWithIndex.flatMap { case (elt, index) => getPortNames(s"${name}_${index}", elt) }
})
modulePorts(target).flatMap {
case (name, data) =>
diff --git a/core/src/main/scala/chisel3/IO.scala b/core/src/main/scala/chisel3/IO.scala
new file mode 100644
index 00000000..1a28db1e
--- /dev/null
+++ b/core/src/main/scala/chisel3/IO.scala
@@ -0,0 +1,41 @@
+package chisel3
+
+import chisel3.internal.requireIsChiselType // Fix ambiguous import
+import chisel3.internal.Builder
+import chisel3.internal.sourceinfo.SourceInfo
+
+object IO {
+
+ /** Constructs a port for the current Module
+ *
+ * This must wrap the datatype used to set the io field of any Module.
+ * i.e. All concrete modules must have defined io in this form:
+ * [lazy] val io[: io type] = IO(...[: io type])
+ *
+ * Items in [] are optional.
+ *
+ * The granted iodef must be a chisel type and not be bound to hardware.
+ *
+ * Also registers a Data as a port, also performing bindings. Cannot be called once ports are
+ * requested (so that all calls to ports will return the same information).
+ * Internal API.
+ */
+ def apply[T <: Data](iodef: T): T = {
+ val module = Module.currentModule.get // Impossible to fail
+ require(!module.isClosed, "Can't add more ports after module close")
+ requireIsChiselType(iodef, "io type")
+
+ // Clone the IO so we preserve immutability of data types
+ val iodefClone =
+ try {
+ iodef.cloneTypeFull
+ } catch {
+ // For now this is going to be just a deprecation so we don't suddenly break everyone's code
+ case e: AutoClonetypeException =>
+ Builder.deprecated(e.getMessage, Some(s"${iodef.getClass}"))
+ iodef
+ }
+ module.bindIoInPlace(iodefClone)
+ iodefClone
+ }
+}
diff --git a/core/src/main/scala/chisel3/Module.scala b/core/src/main/scala/chisel3/Module.scala
index e5c2a848..a2d5cec6 100644
--- a/core/src/main/scala/chisel3/Module.scala
+++ b/core/src/main/scala/chisel3/Module.scala
@@ -200,42 +200,10 @@ abstract class Module(implicit moduleCompileOptions: CompileOptions) extends Raw
}
package experimental {
-
- import chisel3.internal.requireIsChiselType // Fix ambiguous import
-
object IO {
-
- /** Constructs a port for the current Module
- *
- * This must wrap the datatype used to set the io field of any Module.
- * i.e. All concrete modules must have defined io in this form:
- * [lazy] val io[: io type] = IO(...[: io type])
- *
- * Items in [] are optional.
- *
- * The granted iodef must be a chisel type and not be bound to hardware.
- *
- * Also registers a Data as a port, also performing bindings. Cannot be called once ports are
- * requested (so that all calls to ports will return the same information).
- * Internal API.
- */
+ @deprecated("chisel3.experimental.IO is deprecated, use chisel3.IO instead", "Chisel 3.5")
def apply[T <: Data](iodef: T): T = {
- val module = Module.currentModule.get // Impossible to fail
- require(!module.isClosed, "Can't add more ports after module close")
- requireIsChiselType(iodef, "io type")
-
- // Clone the IO so we preserve immutability of data types
- val iodefClone =
- try {
- iodef.cloneTypeFull
- } catch {
- // For now this is going to be just a deprecation so we don't suddenly break everyone's code
- case e: AutoClonetypeException =>
- Builder.deprecated(e.getMessage, Some(s"${iodef.getClass}"))
- iodef
- }
- module.bindIoInPlace(iodefClone)
- iodefClone
+ chisel3.IO.apply(iodef)
}
}
}
@@ -753,7 +721,7 @@ package experimental {
* TODO(twigg): Specifically walk the Data definition to call out which nodes
* are problematic.
*/
- protected def IO[T <: Data](iodef: T): T = chisel3.experimental.IO.apply(iodef)
+ protected def IO[T <: Data](iodef: T): T = chisel3.IO.apply(iodef)
//
// Internal Functions
diff --git a/core/src/main/scala/chisel3/SeqUtils.scala b/core/src/main/scala/chisel3/SeqUtils.scala
index b1136120..9d975349 100644
--- a/core/src/main/scala/chisel3/SeqUtils.scala
+++ b/core/src/main/scala/chisel3/SeqUtils.scala
@@ -64,7 +64,10 @@ private[chisel3] object SeqUtils {
if (in.size == 1) {
in.head._2
} else {
- Mux(in.head._1, in.head._2, priorityMux(in.tail))
+ val r = in.view.reverse
+ r.tail.foldLeft(r.head._2) {
+ case (alt, (sel, elt)) => Mux(sel, elt, alt)
+ }
}
}
diff --git a/core/src/main/scala/chisel3/experimental/package.scala b/core/src/main/scala/chisel3/experimental/package.scala
index 39131943..42ec9666 100644
--- a/core/src/main/scala/chisel3/experimental/package.scala
+++ b/core/src/main/scala/chisel3/experimental/package.scala
@@ -72,7 +72,7 @@ package object experimental {
val ports: Seq[Data] =
gen.elements.toSeq.reverse.map {
case (name, data) =>
- val p = IO(coerceDirection(chiselTypeClone(data).asInstanceOf[Data]))
+ val p = chisel3.IO(coerceDirection(chiselTypeClone(data).asInstanceOf[Data]))
p.suggestName(name)
p
diff --git a/core/src/main/scala/chisel3/internal/Builder.scala b/core/src/main/scala/chisel3/internal/Builder.scala
index e3dfff09..d06b7992 100644
--- a/core/src/main/scala/chisel3/internal/Builder.scala
+++ b/core/src/main/scala/chisel3/internal/Builder.scala
@@ -17,18 +17,29 @@ import chisel3.internal.Builder.Prefix
import logger.LazyLogging
import scala.collection.mutable
+import scala.annotation.tailrec
private[chisel3] class Namespace(keywords: Set[String]) {
+ // This HashMap is compressed, not every name in the namespace is present here.
+ // If the same name is requested multiple times, it only takes 1 entry in the HashMap and the
+ // value is incremented for each time the name is requested.
+ // Names can be requested that collide with compressed sets of names, thus the algorithm for
+ // checking if a name is present in the Namespace is more complex than just checking the HashMap,
+ // see getIndex below.
private val names = collection.mutable.HashMap[String, Long]()
def copyTo(other: Namespace): Unit = names.foreach { case (s: String, l: Long) => other.names(s) = l }
for (keyword <- keywords)
names(keyword) = 1
- private def rename(n: String): String = {
- val index = names(n)
+ @tailrec
+ private def rename(n: String, index: Long): String = {
val tryName = s"${n}_${index}"
- names(n) = index + 1
- if (this contains tryName) rename(n) else tryName
+ if (names.contains(tryName)) {
+ rename(n, index + 1)
+ } else {
+ names(n) = index + 1
+ tryName
+ }
}
private def sanitize(s: String, leadingDigitOk: Boolean = false): String = {
@@ -40,14 +51,50 @@ private[chisel3] class Namespace(keywords: Set[String]) {
if (headOk) res else s"_$res"
}
- def contains(elem: String): Boolean = names.contains(elem)
+ /** Checks if `n` ends in `_\d+` and returns the substring before `_` if so, null otherwise */
+ // TODO can and should this be folded in to sanitize? Same iteration as the forall?
+ private def prefix(n: String): Int = {
+ // This is micro-optimized because it runs on every single name
+ var i = n.size - 1
+ while (i > 0 && n(i).isDigit) {
+ i -= 1
+ }
+ // Will get i == 0 for all digits or _\d+ with empty prefix, those have no prefix so returning 0 is correct
+ if (i == n.size) 0 // no digits
+ else if (n(i) != '_') 0 // no _
+ else i
+ }
+
+ // Gets the current index for this name, None means it is not contained in the Namespace
+ private def getIndex(elem: String): Option[Long] =
+ names.get(elem).orElse {
+ // This exact name isn't contained, but if we end in _<idx>, we need to check our prefix
+ val maybePrefix = prefix(elem)
+ if (maybePrefix == 0) None
+ else {
+ // If we get a prefix collision and our index is taken, we start disambiguating with _<idx>_1
+ names
+ .get(elem.take(maybePrefix))
+ .filter { prefixIdx =>
+ val ourIdx = elem.drop(maybePrefix + 1).toInt
+ // The namespace starts disambiguating at _1 so _0 is a false collision case
+ ourIdx != 0 && prefixIdx > ourIdx
+ }
+ .map(_ => 1)
+ }
+ }
+
+ def contains(elem: String): Boolean = getIndex(elem).isDefined
// leadingDigitOk is for use in fields of Records
def name(elem: String, leadingDigitOk: Boolean = false): String = {
val sanitized = sanitize(elem, leadingDigitOk)
- val result = if (this.contains(sanitized)) rename(sanitized) else sanitized
- names(result) = 1
- result
+ getIndex(sanitized) match {
+ case Some(idx) => rename(sanitized, idx)
+ case None =>
+ names(sanitized) = 1
+ sanitized
+ }
}
}