summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJack2023-01-08 04:47:27 +0000
committerJack2023-01-08 04:47:27 +0000
commit5aa60ecda6bd2b02dfc7253a47e53c7647981a5c (patch)
tree53ea2570c4af7824d6203e0c0cd7953c1ba4910c
parenta50a5a287a23ba6b833b13d8cec84dd5dfe0fc61 (diff)
parent116210ff806ccdda91b4c3343f78bad66783d0e6 (diff)
Merge branch '3.5.x' into 3.5-release
-rw-r--r--.github/workflows/install-espresso/action.yml25
-rw-r--r--.github/workflows/setup-oss-cad-suite/action.yml28
-rw-r--r--.github/workflows/test.yml77
-rw-r--r--build.sbt1
-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
-rw-r--r--src/main/scala/chisel3/util/experimental/decode/decoder.scala6
-rw-r--r--src/test/scala/chisel3/internal/NamespaceSpec.scala81
-rw-r--r--src/test/scala/chiselTests/RecordSpec.scala20
-rw-r--r--src/test/scala/chiselTests/experimental/FlatIOSpec.scala8
-rw-r--r--src/test/scala/chiselTests/util/BitSetSpec.scala29
-rw-r--r--src/test/scala/chiselTests/util/PriorityMuxSpec.scala60
16 files changed, 394 insertions, 99 deletions
diff --git a/.github/workflows/install-espresso/action.yml b/.github/workflows/install-espresso/action.yml
new file mode 100644
index 00000000..fb1d655a
--- /dev/null
+++ b/.github/workflows/install-espresso/action.yml
@@ -0,0 +1,25 @@
+name: Install Espresso
+
+inputs:
+ version:
+ description: 'version to install'
+ required: false
+ default: '2.4'
+
+runs:
+ using: composite
+ steps:
+ - id: cache-espresso
+ uses: actions/cache@v3
+ with:
+ path: /usr/local/bin/espresso
+ key: espresso-${{ runner.os }}-${{ inputs.version }}
+
+ - shell: bash
+ if: steps.cache-espresso.outputs.cache-hit != 'true'
+ run: |
+ cd /tmp
+ wget -q https://github.com/chipsalliance/espresso/releases/download/v${{ inputs.version }}/x86_64-linux-gnu-espresso
+ chmod +x x86_64-linux-gnu-espresso
+ sudo mv x86_64-linux-gnu-espresso /usr/local/bin/espresso
+ espresso || true
diff --git a/.github/workflows/setup-oss-cad-suite/action.yml b/.github/workflows/setup-oss-cad-suite/action.yml
new file mode 100644
index 00000000..63d70e92
--- /dev/null
+++ b/.github/workflows/setup-oss-cad-suite/action.yml
@@ -0,0 +1,28 @@
+name: Setup OSS CAD Suite
+
+inputs:
+ version:
+ description: 'version to install'
+ required: false
+ default: '2021-11-09'
+
+runs:
+ using: composite
+ steps:
+ - id: cache-oss-cad-suite
+ uses: actions/cache@v3
+ with:
+ path: oss-cad-suite
+ key: oss-cad-suite-${{ runner.os }}-${{ inputs.version }}
+
+ - shell: bash
+ if: steps.cache-oss-cad-suite.outputs.cache-hit != 'true'
+ run: |
+ VERSION=${{ inputs.version }}
+ ARTIFACT=oss-cad-suite-linux-x64-$(echo $VERSION | tr -d '-')
+ wget -q -O - https://github.com/YosysHQ/oss-cad-suite-build/releases/download/${VERSION}/${ARTIFACT}.tgz | tar -zx
+
+ # Add the CAD Suite to the PATH
+ - shell: bash
+ run: echo "$(pwd)/oss-cad-suite/bin" >> $GITHUB_PATH
+
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 69426662..dd129812 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -16,34 +16,26 @@ jobs:
strategy:
matrix:
system: ["ubuntu-20.04"]
- jvm: ["adopt@1.8"]
+ jvm: ["8"]
scala: ["2.13.10", "2.12.17"]
espresso: ["2.4"]
runs-on: ${{ matrix.system }}
steps:
- name: Checkout
- uses: actions/checkout@v2
-
- - name: Install Tabby OSS Cad Suite (from YosysHQ)
- uses: YosysHQ/setup-oss-cad-suite@v1
- with:
- osscadsuite-version: '2021-11-09'
-
+ uses: actions/checkout@v3
+ - name: Install Tabby OSS Cad Suite
+ uses: ./.github/workflows/setup-oss-cad-suite
- name: Install Espresso
- run: |
- cd /tmp
- wget https://github.com/chipsalliance/espresso/releases/download/v${{ matrix.espresso }}/x86_64-linux-gnu-espresso
- chmod +x x86_64-linux-gnu-espresso
- sudo mv x86_64-linux-gnu-espresso /usr/local/bin/espresso
- espresso || true
-
+ uses: ./.github/workflows/install-espresso
+ with:
+ version: ${{ matrix.espresso }}
- name: Setup Scala
- uses: olafurpg/setup-scala@v10
+ uses: actions/setup-java@v3
with:
+ distribution: 'adopt'
java-version: ${{ matrix.jvm }}
- - name: Cache Scala
- uses: coursier/cache-action@v5
+ cache: 'sbt'
- name: Use Treadle for Pull Requests
if: github.event_name == 'pull_request'
run: echo "CHISEL3_CI_USE_TREADLE=1" >> $GITHUB_ENV
@@ -57,13 +49,13 @@ jobs:
runs-on: ubuntu-20.04
steps:
- name: Checkout
- uses: actions/checkout@v2
+ uses: actions/checkout@v3
- name: Setup Scala
- uses: olafurpg/setup-scala@v10
+ uses: actions/setup-java@v3
with:
- java-version: "adopt@1.11"
- - name: Cache Scala
- uses: coursier/cache-action@v5
+ distribution: 'adopt'
+ java-version: '11'
+ cache: 'sbt'
- name: Check Formatting
run: sbt scalafmtCheckAll
- name: Documentation
@@ -74,24 +66,17 @@ jobs:
runs-on: ubuntu-20.04
steps:
- name: Checkout
- uses: actions/checkout@v2
- - name: Install Tabby OSS Cad Suite (from YosysHQ)
- uses: YosysHQ/setup-oss-cad-suite@v1
- with:
- osscadsuite-version: '2021-11-09'
+ uses: actions/checkout@v3
+ - name: Install Tabby OSS Cad Suite
+ uses: ./.github/workflows/setup-oss-cad-suite
- name: Install Espresso
- run: |
- cd /tmp
- wget https://github.com/chipsalliance/espresso/releases/download/v2.4/x86_64-linux-gnu-espresso
- chmod +x x86_64-linux-gnu-espresso
- sudo mv x86_64-linux-gnu-espresso /usr/local/bin/espresso
- espresso || true
+ uses: ./.github/workflows/install-espresso
- name: Setup Scala
- uses: olafurpg/setup-scala@v10
+ uses: actions/setup-java@v3
with:
- java-version: "adopt@1.11"
- - name: Cache Scala
- uses: coursier/cache-action@v5
+ distribution: 'adopt'
+ java-version: '11'
+ cache: 'sbt'
- name: Integration Tests
run: sbt integrationTests/test
@@ -108,7 +93,7 @@ jobs:
success: ${{ steps.setoutput.outputs.success }}
steps:
- id: setoutput
- run: echo "::set-output name=success::true"
+ run: echo "success=true" >> $GITHUB_OUTPUT
# Related to check-tests above, this job _always_ runs (even if tests fail
# and thus check-steps is skipped). This two sentinel job approach avoids an
@@ -126,10 +111,10 @@ jobs:
- run: |
PASSED="${{ needs.check-tests.outputs.success }}"
if [[ $PASSED == "true" ]]; then
- echo "All tests passed!"
+ echo "### All tests passed! :rocket:" >> $GITHUB_STEP_SUMMARY
exit 0
else
- echo "One or more tests FAILED!"
+ echo "### One or more tests FAILED! :bangbang:" >> $GITHUB_STEP_SUMMARY
exit 1
fi
@@ -142,13 +127,13 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v2
+ uses: actions/checkout@v3
- name: Setup Scala
- uses: olafurpg/setup-scala@v10
+ uses: actions/setup-java@v3
with:
- java-version: adopt@1.8
- - name: Cache Scala
- uses: coursier/cache-action@v5
+ distribution: 'adopt'
+ java-version: '8'
+ cache: 'sbt'
- name: Setup GPG (for Publish)
uses: olafurpg/setup-gpg@v3
- name: Publish
diff --git a/build.sbt b/build.sbt
index d0692dae..9d89766f 100644
--- a/build.sbt
+++ b/build.sbt
@@ -38,6 +38,7 @@ lazy val commonSettings = Seq (
)
lazy val publishSettings = Seq (
+ versionScheme := Some("pvp"),
publishMavenStyle := true,
publishArtifact in Test := false,
pomIncludeRepository := { x => false },
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
+ }
}
}
diff --git a/src/main/scala/chisel3/util/experimental/decode/decoder.scala b/src/main/scala/chisel3/util/experimental/decode/decoder.scala
index 067dd6f8..ce2da3c0 100644
--- a/src/main/scala/chisel3/util/experimental/decode/decoder.scala
+++ b/src/main/scala/chisel3/util/experimental/decode/decoder.scala
@@ -107,8 +107,10 @@ object decoder extends LazyLogging {
{
bitSets.zipWithIndex.flatMap {
case (bs, i) =>
- bs.terms.map(bp => s"${bp.rawString}->${if (errorBit) "0"}${"0" * (bitSets.size - i - 1)}1${"0" * i}")
- } ++ Seq(s"${if (errorBit) "1"}${"?" * bitSets.size}")
+ bs.terms.map(bp =>
+ s"${bp.rawString}->${if (errorBit) "0" else ""}${"0" * (bitSets.size - i - 1)}1${"0" * i}"
+ )
+ } ++ Seq(s"${if (errorBit) "1" ++ "0" * bitSets.size else "?" * bitSets.size}")
}.mkString("\n")
)
)
diff --git a/src/test/scala/chisel3/internal/NamespaceSpec.scala b/src/test/scala/chisel3/internal/NamespaceSpec.scala
new file mode 100644
index 00000000..fd808ff0
--- /dev/null
+++ b/src/test/scala/chisel3/internal/NamespaceSpec.scala
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: Apache-2.0
+
+package chisel3.internal
+
+import org.scalatest.flatspec.AnyFlatSpec
+import org.scalatest.matchers.should.Matchers._
+
+class NamespaceSpec extends AnyFlatSpec {
+ behavior.of("Namespace")
+
+ they should "support basic disambiguation" in {
+ val namespace = Namespace.empty
+ val name = namespace.name(_, false)
+ name("x") should be("x")
+ name("x") should be("x_1")
+ name("x") should be("x_2")
+ }
+
+ they should "support explicit <prefix>_# names before <prefix> names" in {
+ val namespace = Namespace.empty
+ val name = namespace.name(_, false)
+ name("x_1") should be("x_1")
+ name("x_2") should be("x_2")
+ name("x") should be("x")
+ name("x") should be("x_3")
+ }
+
+ they should "support explicit <prefix>_# names in the middle of <prefix> names" in {
+ val namespace = Namespace.empty
+ val name = namespace.name(_, false)
+ name("x") should be("x")
+ name("x") should be("x_1")
+ name("x_1") should be("x_1_1")
+ name("x_2") should be("x_2")
+ name("x") should be("x_3")
+ }
+
+ // For some reason, multi-character names tickled a different failure mode than single character
+ they should "support explicit <prefix>_# names in the middle of longer <prefix> names" in {
+ val namespace = Namespace.empty
+ val name = namespace.name(_, false)
+ name("foo") should be("foo")
+ name("foo") should be("foo_1")
+ name("foo_1") should be("foo_1_1")
+ name("foo_2") should be("foo_2")
+ name("foo") should be("foo_3")
+ }
+
+ they should "support collisions in recursively growing names" in {
+ val namespace = Namespace.empty
+ val name = namespace.name(_, false)
+ name("x") should be("x")
+ name("x") should be("x_1")
+ name("x_1") should be("x_1_1")
+ name("x_1") should be("x_1_2")
+ name("x_1_1") should be("x_1_1_1")
+ name("x_1_1") should be("x_1_1_2")
+ }
+
+ they should "support collisions in recursively shrinking names" in {
+ val namespace = Namespace.empty
+ val name = namespace.name(_, false)
+ name("x_1_1") should be("x_1_1")
+ name("x_1_1") should be("x_1_1_1")
+ name("x_1") should be("x_1")
+ name("x_1") should be("x_1_2")
+ name("x") should be("x")
+ name("x") should be("x_2")
+ }
+
+ // The namespace never generates names with _0 so it's actually a false collision case
+ they should "properly handle false collisions with signals ending in _0" in {
+ val namespace = Namespace.empty
+ val name = namespace.name(_, false)
+ name("x") should be("x")
+ name("x") should be("x_1")
+ name("x_0") should be("x_0")
+ name("x") should be("x_2")
+ name("x_0") should be("x_0_1")
+ }
+}
diff --git a/src/test/scala/chiselTests/RecordSpec.scala b/src/test/scala/chiselTests/RecordSpec.scala
index 3414ec8a..5a5bcf67 100644
--- a/src/test/scala/chiselTests/RecordSpec.scala
+++ b/src/test/scala/chiselTests/RecordSpec.scala
@@ -284,6 +284,26 @@ class RecordSpec extends ChiselFlatSpec with RecordSpecUtils with Utils {
testStrings.foreach(x => assert(x == "~NestedRecordModule|InnerModule>io.foo"))
}
+ they should "work correctly with DataMirror in nested OpaqueType Records" in {
+ var mod: NestedRecordModule = null
+ ChiselStage.elaborate { mod = new NestedRecordModule; mod }
+ val ports = chisel3.experimental.DataMirror.fullModulePorts(mod.inst)
+ val expectedPorts = Seq(
+ ("clock", mod.inst.clock),
+ ("reset", mod.inst.reset),
+ ("io", mod.inst.io),
+ ("io_bar", mod.inst.io.bar),
+ ("io_bar", mod.inst.io.bar.k),
+ ("io_bar", mod.inst.io.bar.k.k),
+ ("io_bar", mod.inst.io.bar.k.k.elements.head._2),
+ ("io_foo", mod.inst.io.foo),
+ ("io_foo", mod.inst.io.foo.k),
+ ("io_foo", mod.inst.io.foo.k.k),
+ ("io_foo", mod.inst.io.foo.k.k.elements.head._2)
+ )
+ ports shouldBe expectedPorts
+ }
+
they should "work correctly when connecting nested OpaqueType elements" in {
val nestedRecordChirrtl = ChiselStage.emitChirrtl { new NestedRecordModule }
nestedRecordChirrtl should include("input in : UInt<8>")
diff --git a/src/test/scala/chiselTests/experimental/FlatIOSpec.scala b/src/test/scala/chiselTests/experimental/FlatIOSpec.scala
index ebb7cbdb..fb3f64c7 100644
--- a/src/test/scala/chiselTests/experimental/FlatIOSpec.scala
+++ b/src/test/scala/chiselTests/experimental/FlatIOSpec.scala
@@ -55,9 +55,11 @@ class FlatIOSpec extends ChiselFlatSpec {
val bar = Analog(8.W)
}
class MyModule extends RawModule {
- val in = IO(Flipped(new MyBundle))
- val out = IO(new MyBundle)
- out <> in
+ val io = FlatIO(new Bundle {
+ val in = Flipped(new MyBundle)
+ val out = new MyBundle
+ })
+ io.out <> io.in
}
val chirrtl = emitChirrtl(new MyModule)
chirrtl should include("out.foo <= in.foo")
diff --git a/src/test/scala/chiselTests/util/BitSetSpec.scala b/src/test/scala/chiselTests/util/BitSetSpec.scala
index dd66ba40..cf5f54cf 100644
--- a/src/test/scala/chiselTests/util/BitSetSpec.scala
+++ b/src/test/scala/chiselTests/util/BitSetSpec.scala
@@ -110,9 +110,36 @@ class BitSetSpec extends AnyFlatSpec with Matchers {
"b11??????"
)
),
- true
+ errorBit = true
)
})
}
+ it should "be decoded with DontCare error" in {
+ import chisel3._
+ import chisel3.util.experimental.decode.decoder
+ // [0 - 256] part into: [0 - 31], [32 - 47, 64 - 127], [192 - 255]
+ // "0011????" "10??????" is empty to error
+ chisel3.stage.ChiselStage.emitSystemVerilog(new Module {
+ val in = IO(Input(UInt(8.W)))
+ val out = IO(Output(UInt(4.W)))
+ out := decoder.bitset(
+ in,
+ Seq(
+ BitSet.fromString(
+ "b000?????"
+ ),
+ BitSet.fromString(
+ """b0010????
+ |b01??????
+ |""".stripMargin
+ ),
+ BitSet.fromString(
+ "b11??????"
+ )
+ ),
+ errorBit = false
+ )
+ })
+ }
}
diff --git a/src/test/scala/chiselTests/util/PriorityMuxSpec.scala b/src/test/scala/chiselTests/util/PriorityMuxSpec.scala
new file mode 100644
index 00000000..32cf2431
--- /dev/null
+++ b/src/test/scala/chiselTests/util/PriorityMuxSpec.scala
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: Apache-2.0
+
+package chiselTests.util
+
+import chisel3._
+import chisel3.util.{is, switch, Counter, PriorityMux}
+import chisel3.testers.BasicTester
+import chisel3.stage.ChiselStage.emitChirrtl
+
+import chiselTests.ChiselFlatSpec
+
+class PriorityMuxTester extends BasicTester {
+
+ val sel = Wire(UInt(3.W))
+ sel := 0.U // default
+
+ val elts = Seq(5.U, 6.U, 7.U)
+ val muxed = PriorityMux(sel, elts)
+
+ // Priority is given to lowest order bit
+ val tests = Seq(
+ 1.U -> elts(0),
+ 2.U -> elts(1),
+ 3.U -> elts(0),
+ 4.U -> elts(2),
+ 5.U -> elts(0),
+ 6.U -> elts(1),
+ 7.U -> elts(0)
+ )
+ val (cycle, done) = Counter(0 until tests.size + 1)
+
+ for (((in, out), idx) <- tests.zipWithIndex) {
+ when(cycle === idx.U) {
+ sel := in
+ assert(muxed === out)
+ }
+ }
+
+ when(done) {
+ stop()
+ }
+}
+
+class PriorityMuxSpec extends ChiselFlatSpec {
+ behavior.of("PriorityMux")
+
+ it should "be functionally correct" in {
+ assertTesterPasses(new PriorityMuxTester)
+ }
+
+ it should "be stack safe" in {
+ emitChirrtl(new RawModule {
+ val n = 1 << 15
+ val in = IO(Input(Vec(n, UInt(8.W))))
+ val sel = IO(Input(UInt(n.W)))
+ val out = IO(Output(UInt(8.W)))
+ out := PriorityMux(sel, in)
+ })
+ }
+}