summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/ISSUE_TEMPLATE.md2
-rw-r--r--.github/workflows/test.yml40
-rw-r--r--CONTRIBUTING.md16
-rw-r--r--README.md40
-rw-r--r--build.sbt24
-rw-r--r--build.sc4
-rw-r--r--core/src/main/scala/chisel3/Aggregate.scala287
-rw-r--r--core/src/main/scala/chisel3/Assert.scala92
-rw-r--r--core/src/main/scala/chisel3/Bits.scala204
-rw-r--r--core/src/main/scala/chisel3/BlackBox.scala3
-rw-r--r--core/src/main/scala/chisel3/Clock.scala10
-rw-r--r--core/src/main/scala/chisel3/Data.scala133
-rw-r--r--core/src/main/scala/chisel3/Mem.scala2
-rw-r--r--core/src/main/scala/chisel3/Module.scala83
-rw-r--r--core/src/main/scala/chisel3/Num.scala5
-rw-r--r--core/src/main/scala/chisel3/Printf.scala3
-rw-r--r--core/src/main/scala/chisel3/RawModule.scala20
-rw-r--r--core/src/main/scala/chisel3/Reg.scala4
-rw-r--r--core/src/main/scala/chisel3/SeqUtils.scala2
-rw-r--r--core/src/main/scala/chisel3/StrongEnum.scala23
-rw-r--r--core/src/main/scala/chisel3/VerificationStatement.scala236
-rw-r--r--core/src/main/scala/chisel3/When.scala9
-rw-r--r--core/src/main/scala/chisel3/experimental/Analog.scala4
-rw-r--r--core/src/main/scala/chisel3/experimental/Trace.scala69
-rw-r--r--core/src/main/scala/chisel3/experimental/dataview/DataProduct.scala248
-rw-r--r--core/src/main/scala/chisel3/experimental/dataview/DataView.scala239
-rw-r--r--core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala23
-rw-r--r--core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala112
-rw-r--r--core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala54
-rw-r--r--core/src/main/scala/chisel3/experimental/hierarchy/IsInstantiable.scala2
-rw-r--r--core/src/main/scala/chisel3/experimental/hierarchy/LibraryHooks.scala31
-rw-r--r--core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala102
-rw-r--r--core/src/main/scala/chisel3/experimental/hierarchy/Underlying.scala14
-rw-r--r--core/src/main/scala/chisel3/experimental/package.scala150
-rw-r--r--core/src/main/scala/chisel3/experimental/verification/package.scala60
-rw-r--r--core/src/main/scala/chisel3/internal/Builder.scala92
-rw-r--r--core/src/main/scala/chisel3/internal/MonoConnect.scala72
-rw-r--r--core/src/main/scala/chisel3/internal/firrtl/Converter.scala7
-rw-r--r--core/src/main/scala/chisel3/internal/firrtl/IR.scala27
-rw-r--r--core/src/main/scala/chisel3/internal/plugin/package.scala19
-rw-r--r--core/src/main/scala/chisel3/internal/prefix.scala4
-rw-r--r--core/src/main/scala/chisel3/package.scala26
-rw-r--r--docs/README.md8
-rw-r--r--docs/src/appendix/appendix.md1
-rw-r--r--docs/src/appendix/experimental-features.md2
-rw-r--r--docs/src/appendix/upgrading-from-chisel-3-4.md145
-rw-r--r--docs/src/appendix/upgrading-from-scala-2-11.md2
-rw-r--r--docs/src/appendix/versioning.md22
-rw-r--r--docs/src/cookbooks/cookbook.md39
-rw-r--r--docs/src/cookbooks/cookbooks.md2
-rw-r--r--docs/src/cookbooks/hierarchy.md57
-rw-r--r--docs/src/cookbooks/naming.md2
-rw-r--r--docs/src/explanations/blackboxes.md3
-rw-r--r--docs/src/explanations/bundles-and-vecs.md67
-rw-r--r--docs/src/explanations/dataview.md46
-rw-r--r--docs/src/explanations/explanations.md1
-rw-r--r--docs/src/explanations/functional-abstraction.md8
-rw-r--r--docs/src/explanations/modules.md4
-rw-r--r--docs/src/explanations/multi-clock.md2
-rw-r--r--docs/src/explanations/naming.md1
-rw-r--r--integration-tests/src/test/scala/chiselTests/util/experimental/DecoderSpec.scala4
-rw-r--r--integration-tests/src/test/scala/chiselTests/util/experimental/minimizer/MinimizerSpec.scala2
-rw-r--r--macros/src/main/scala/chisel3/internal/InstantiableMacro.scala25
-rw-r--r--macros/src/main/scala/chisel3/internal/sourceinfo/SourceInfoTransform.scala14
l---------no-plugin-tests/src/test/scala/chisel3/testers/TestUtils.scala1
l---------no-plugin-tests/src/test/scala/chiselTests/AutoClonetypeSpec.scala1
l---------no-plugin-tests/src/test/scala/chiselTests/AutoNestedCloneSpec.scala1
l---------no-plugin-tests/src/test/scala/chiselTests/BetterNamingTests.scala1
l---------no-plugin-tests/src/test/scala/chiselTests/CatSpec.scala1
l---------no-plugin-tests/src/test/scala/chiselTests/ChiselSpec.scala1
l---------no-plugin-tests/src/test/scala/chiselTests/CustomBundle.scala1
l---------no-plugin-tests/src/test/scala/chiselTests/InstanceNameSpec.scala1
-rw-r--r--no-plugin-tests/src/test/scala/chiselTests/MissingCloneBindingExceptionSpec.scala55
l---------no-plugin-tests/src/test/scala/chiselTests/NamingAnnotationTest.scala1
-rw-r--r--plugin/src/main/scala/chisel3/internal/plugin/BundleComponent.scala5
-rw-r--r--project/build.properties2
-rw-r--r--project/plugins.sbt14
-rw-r--r--src/main/scala/chisel3/ChiselExecutionOptions.scala49
-rw-r--r--src/main/scala/chisel3/Driver.scala145
-rw-r--r--src/main/scala/chisel3/aop/Select.scala180
-rw-r--r--src/main/scala/chisel3/aop/injecting/InjectingAspect.scala2
-rw-r--r--src/main/scala/chisel3/compatibility.scala9
-rw-r--r--src/main/scala/chisel3/experimental/conversions/package.scala128
-rw-r--r--src/main/scala/chisel3/experimental/verification/package.scala27
-rw-r--r--src/main/scala/chisel3/stage/package.scala29
-rw-r--r--src/main/scala/chisel3/stage/phases/DriverCompatibility.scala16
-rw-r--r--src/main/scala/chisel3/testers/BasicTester.scala7
-rw-r--r--src/main/scala/chisel3/util/Arbiter.scala17
-rw-r--r--src/main/scala/chisel3/util/BitPat.scala218
-rw-r--r--src/main/scala/chisel3/util/Decoupled.scala110
-rw-r--r--src/main/scala/chisel3/util/Enum.scala1
-rw-r--r--src/main/scala/chisel3/util/Valid.scala23
-rw-r--r--src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala15
-rw-r--r--src/main/scala/chisel3/util/experimental/decode/QMCMinimizer.scala19
-rw-r--r--src/main/scala/chisel3/util/experimental/decode/TruthTable.scala47
-rw-r--r--src/main/scala/chisel3/util/experimental/decode/decoder.scala35
-rw-r--r--src/main/scala/chisel3/util/random/GaloisLFSR.scala4
-rw-r--r--src/main/scala/chisel3/util/random/PRNG.scala15
-rw-r--r--src/test/scala/chisel3/testers/TestUtils.scala9
-rw-r--r--src/test/scala/chiselTests/AutoClonetypeSpec.scala199
-rw-r--r--src/test/scala/chiselTests/AutoNestedCloneSpec.scala65
-rw-r--r--src/test/scala/chiselTests/BlackBoxImpl.scala1
-rw-r--r--src/test/scala/chiselTests/BundleSpec.scala33
-rw-r--r--src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala5
-rw-r--r--src/test/scala/chiselTests/CompatibilitySpec.scala33
-rw-r--r--src/test/scala/chiselTests/CompileOptionsTest.scala2
-rw-r--r--src/test/scala/chiselTests/ComplexAssign.scala5
-rw-r--r--src/test/scala/chiselTests/ConnectSpec.scala35
-rw-r--r--src/test/scala/chiselTests/DataPrint.scala56
-rw-r--r--src/test/scala/chiselTests/FixedPointSpec.scala3
-rw-r--r--src/test/scala/chiselTests/Harness.scala5
-rw-r--r--src/test/scala/chiselTests/InlineSpec.scala1
-rw-r--r--src/test/scala/chiselTests/IntervalSpec.scala9
-rw-r--r--src/test/scala/chiselTests/InvalidateAPISpec.scala2
-rw-r--r--src/test/scala/chiselTests/LoadMemoryFromFileSpec.scala1
-rw-r--r--src/test/scala/chiselTests/Module.scala66
-rw-r--r--src/test/scala/chiselTests/PrintableSpec.scala9
-rw-r--r--src/test/scala/chiselTests/QueueFlushSpec.scala20
-rw-r--r--src/test/scala/chiselTests/QueueSpec.scala30
-rw-r--r--src/test/scala/chiselTests/RecordSpec.scala25
-rw-r--r--src/test/scala/chiselTests/SIntOps.scala2
-rw-r--r--src/test/scala/chiselTests/StrongEnum.scala4
-rw-r--r--src/test/scala/chiselTests/TransitNameSpec.scala1
-rw-r--r--src/test/scala/chiselTests/UIntOps.scala84
-rw-r--r--src/test/scala/chiselTests/Vec.scala34
-rw-r--r--src/test/scala/chiselTests/VecLiteralSpec.scala48
-rw-r--r--src/test/scala/chiselTests/VerificationSpec.scala (renamed from src/test/scala/chiselTests/experimental/verification/VerificationSpec.scala)35
-rw-r--r--src/test/scala/chiselTests/aop/SelectSpec.scala7
-rw-r--r--src/test/scala/chiselTests/experimental/DataView.scala123
-rw-r--r--src/test/scala/chiselTests/experimental/DataViewTargetSpec.scala3
-rw-r--r--src/test/scala/chiselTests/experimental/TraceSpec.scala309
-rw-r--r--src/test/scala/chiselTests/experimental/Tuple.scala163
-rw-r--r--src/test/scala/chiselTests/experimental/hierarchy/Annotations.scala12
-rw-r--r--src/test/scala/chiselTests/experimental/hierarchy/DefinitionSpec.scala55
-rw-r--r--src/test/scala/chiselTests/experimental/hierarchy/Examples.scala53
-rw-r--r--src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala156
-rw-r--r--src/test/scala/chiselTests/util/BitPatSpec.scala10
-rw-r--r--src/test/scala/chiselTests/util/BitSetSpec.scala119
-rw-r--r--src/test/scala/chiselTests/util/experimental/TruthTableSpec.scala31
139 files changed, 4400 insertions, 1698 deletions
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
index d08788de..b2ce0915 100644
--- a/.github/ISSUE_TEMPLATE.md
+++ b/.github/ISSUE_TEMPLATE.md
@@ -13,7 +13,7 @@ Please select the item best describing the issue in each category and delete the
**Development Phase**: request | proposal
**Other information**
- <!-- include detailed explanation, stacktraces, related issues, suggestions how to fix, links for us to have context, eg. Stack Overflow, gitter, etc -->
+ <!-- include detailed explanation, stacktraces, related issues, suggestions how to fix, links for us to have context, eg. Stack Overflow, gitter, Scastie (https://scastie.scala-lang.org/KtzZQ3nFTea9KoNh0tRqtg) -->
**If the current behavior is a bug, please provide the steps to reproduce the problem:**
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index abce6d13..ce18fab0 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -17,7 +17,6 @@ jobs:
system: ["ubuntu-20.04"]
jvm: ["adopt@1.8"]
scala: ["2.13.6", "2.12.15"]
- verilator: ["4.204"]
espresso: ["2.4"]
runs-on: ${{ matrix.system }}
@@ -25,32 +24,10 @@ jobs:
- name: Checkout
uses: actions/checkout@v2
- - name: Install Z3
- if: matrix.system == 'ubuntu-20.04'
- run: |
- sudo apt-get install -y z3
- z3 --version
-
- - name: Cache Verilator ${{ matrix.verilator }}
- uses: actions/cache@v2.1.6
- id: cache-verilator
+ - name: Install Tabby OSS Cad Suite (from YosysHQ)
+ uses: YosysHQ/setup-oss-cad-suite@v1
with:
- path: verilator-${{ matrix.verilator }}
- key: ${{ matrix.system }}-verilator-${{ matrix.verilator }}
- - name: Compile Verilator ${{ matrix.verilator }}
- if: steps.cache-verilator.outputs.cache-hit != 'true'
- run: |
- wget https://github.com/verilator/verilator/archive/refs/tags/v${{ matrix.verilator }}.tar.gz
- tar xvf v${{ matrix.verilator }}.tar.gz
- cd verilator-${{ matrix.verilator }}
- autoconf
- ./configure
- make
- - name: Install Verilator ${{ matrix.verilator }}
- run: |
- cd verilator-${{ matrix.verilator }}
- sudo make install
- verilator --version
+ osscadsuite-version: '2021-11-09'
- name: Install Espresso
run: |
@@ -70,7 +47,7 @@ jobs:
if: startsWith(matrix.scala, '2.12')
run: sbt ++${{ matrix.scala }} docs/mdoc
- name: Test
- run: sbt ++${{ matrix.scala }} test noPluginTests/test
+ run: sbt ++${{ matrix.scala }} test
- name: Binary compatibility
run: sbt ++${{ matrix.scala }} mimaReportBinaryIssues
@@ -80,11 +57,10 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v2
- - name: Install Verilator and Z3
- run: |
- sudo apt-get install -y verilator z3
- verilator --version
- z3 --version
+ - name: Install Tabby OSS Cad Suite (from YosysHQ)
+ uses: YosysHQ/setup-oss-cad-suite@v1
+ with:
+ osscadsuite-version: '2021-11-09'
- name: Install Espresso
run: |
cd /tmp
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 00000000..06b5200f
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,16 @@
+## GUIDE TO CONTRIBUTING
+
+1. If you need help on making a pull request, follow this [guide](https://docs.github.com/en/github/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests).
+
+2. To understand how to compile and test chisel3 from the source code, follow the instructions in [SETUP.md](https://github.com/chipsalliance/chisel3/blob/master/SETUP.md).
+
+3. In order to contribute to chisel3, you'll need to sign the CLA agreement. You will be asked to sign it upon your first pull request.
+
+<!-- This ones helped me a lot -->
+
+4. To introduce yourself and get help, you can join the [gitter](https://gitter.im/freechipsproject/chisel3) forum. If you have any questions or concerns, you can get help there.
+
+5. You can peruse the [good-first-issues](https://github.com/chipsalliance/chisel3/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) for easy tasks to start with. Another easy thing to start with is doing your own pass of the [website](https://www.chisel-lang.org/chisel3/docs/introduction.html) looking for typos, pages missing their titles, etc. The sources for the website are [here](https://github.com/chipsalliance/chisel3/tree/master/docs).
+
+6. Please make your PRs against the `master` branch. The project admins, when reviewing your PR, will decide which stable version (if any) your change should be backported to. The backports will be opened automatically on your behalf and you may need to do some cleanup, but focus first on your `master` PR.
+
diff --git a/README.md b/README.md
index 60d1dae9..66e27bd9 100644
--- a/README.md
+++ b/README.md
@@ -111,15 +111,24 @@ If you like a textbook to learn Chisel and also a bit of digital design in gener
### Build Your Own Chisel Projects
-See [the setup instructions](https://github.com/chipsalliance/chisel3/blob/master/SETUP.md) for how to set up your environment to run Chisel locally.
+See [the setup instructions](SETUP.md) for how to set up your environment to build Chisel locally.
-When you're ready to build your own circuits in Chisel, **we recommend starting from the [Chisel Template](https://github.com/freechipsproject/chisel-template) repository**, which provides a pre-configured project, example design, and testbench. Follow the [chisel-template readme](https://github.com/freechipsproject/chisel-template) to get started.
+When you're ready to build your own circuits in Chisel, **we recommend starting from the [Chisel Template](https://github.com/freechipsproject/chisel-template) repository**, which provides a pre-configured project, example design, and testbench.
+Follow the [chisel-template README](https://github.com/freechipsproject/chisel-template) to get started.
-If you insist on setting up your own project, the magic SBT lines are:
+If you insist on setting up your own project from scratch, your project needs to depend on both the chisel3-plugin (Scalac plugin) and the chisel3 library.
+For example, in SBT this could be expressed as:
```scala
-libraryDependencies += "edu.berkeley.cs" %% "chisel3" % "3.4.0"
-libraryDependencies += "edu.berkeley.cs" %% "chiseltest" % "0.3.0" % "test"
+// build.sbt
+scalaVersion := "2.12.13"
+addCompilerPlugin("edu.berkeley.cs" % "chisel3-plugin" % "3.4.4" cross CrossVersion.full)
+libraryDependencies += "edu.berkeley.cs" %% "chisel3" % "3.4.4"
+scalacOptions += "-Xsource:2.11"
+// We also recommend using chiseltest for writing unit tests
+libraryDependencies += "edu.berkeley.cs" %% "chiseltest" % "0.3.4" % "test"
```
+### Guide For New Contributors
+If you are trying to make a contribution to this project, please read [CONTRIBUTING.md](https://github.com/Burnleydev1/chisel3/blob/recent_PR/CONTRIBUTING.md)
### Design Verification
@@ -136,6 +145,8 @@ These simulation-based verification tools are available for Chisel:
- [**ScalaDoc**](https://www.chisel-lang.org/api/latest/chisel3/index.html), a listing, description, and examples of the functionality exposed by Chisel
- [**Gitter**](https://gitter.im/freechipsproject/chisel3), where you can ask questions or discuss anything Chisel
- [**Website**](https://www.chisel-lang.org) ([source](https://github.com/freechipsproject/www.chisel-lang.org/))
+- [**Scastie (3.5.0-RC1)**](https://scastie.scala-lang.org/KtzZQ3nFTea9KoNh0tRqtg)
+- [**asic-world**](http://www.asic-world.com/verilog/veritut.html) If you aren't familiar with verilog, this is a good tutorial.
If you are migrating from Chisel2, see [the migration guide](https://www.chisel-lang.org/chisel3/chisel3-vs-chisel2.html).
@@ -155,18 +166,11 @@ The [Useful Resources](#useful-resources) for users are also helpful for contrib
### Compiling and Testing Chisel
-First, clone and build the master branch of [FIRRTL](https://github.com/chipsalliance/firrtl) and [Treadle](https://github.com/chipsalliance/treadle), as the master branch of Chisel may depend on unreleased changes in those projects:
-
-```
-git clone https://github.com/chipsalliance/firrtl.git
-git clone https://github.com/chipsalliance/treadle.git
-pushd firrtl; sbt publishLocal; popd
-pushd treadle; sbt publishLocal; popd
-```
+You must first install required dependencies to build Chisel locally, please see [the setup instructions](SETUP.md).
Clone and build the Chisel library:
-```
+```bash
git clone https://github.com/chipsalliance/chisel3.git
cd chisel3
sbt compile
@@ -185,14 +189,6 @@ If the compilation succeeded and the dependencies noted above are installed, you
sbt test
```
-
-
-If you would like to run the tests without the compiler plugin (less common), you can do so by first launching `sbt`,
-then running `noPluginTests / test`:
-```
-sbt
-> noPluginTests / test
-```
### Running Projects Against Local Chisel
To use the development version of Chisel (`master` branch), you will need to build from source and `publishLocal`.
diff --git a/build.sbt b/build.sbt
index 5de56ac2..4c3d6d5c 100644
--- a/build.sbt
+++ b/build.sbt
@@ -16,7 +16,7 @@ lazy val commonSettings = Seq (
organization := "edu.berkeley.cs",
version := "3.5.0-RC2",
autoAPIMappings := true,
- scalaVersion := "2.13.6",
+ scalaVersion := "2.12.15",
crossScalaVersions := Seq("2.13.6", "2.12.15"),
scalacOptions := Seq("-deprecation", "-feature"),
libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value,
@@ -71,9 +71,9 @@ lazy val chiselSettings = Seq (
name := "chisel3",
libraryDependencies ++= Seq(
- "org.scalatest" %% "scalatest" % "3.2.9" % "test",
+ "org.scalatest" %% "scalatest" % "3.2.10" % "test",
"org.scalatestplus" %% "scalacheck-1-14" % "3.2.2.0" % "test",
- "com.lihaoyi" %% "os-lib" % "0.7.8",
+ "com.lihaoyi" %% "os-lib" % "0.8.0",
),
) ++ (
// Tests from other projects may still run concurrently
@@ -113,7 +113,8 @@ lazy val pluginScalaVersions = Seq(
"2.13.3",
"2.13.4",
"2.13.5",
- "2.13.6"
+ "2.13.6",
+ "2.13.7"
)
lazy val plugin = (project in file("plugin")).
@@ -220,15 +221,6 @@ lazy val chisel = (project in file(".")).
)
)
-lazy val noPluginTests = (project in file ("no-plugin-tests")).
- dependsOn(chisel).
- settings(commonSettings: _*).
- settings(chiselSettings: _*).
- settings(Seq(
- // Totally don't know why GitHub Action won't introduce FIRRTL to dependency.
- libraryDependencies += defaultVersions("firrtl"),
- ))
-
// tests elaborating and executing/formally verifying a Chisel circuit with chiseltest
lazy val integrationTests = (project in file ("integration-tests")).
dependsOn(chisel).
@@ -246,7 +238,11 @@ lazy val docs = project // new documentation project
.settings(usePluginSettings: _*)
.settings(commonSettings)
.settings(
- scalacOptions += "-language:reflectiveCalls",
+ scalacOptions ++= Seq(
+ "-Xfatal-warnings",
+ "-language:reflectiveCalls",
+ "-language:implicitConversions"
+ ),
mdocIn := file("docs/src"),
mdocOut := file("docs/generated"),
// None of our links are hygienic because they're primarily used on the website with .html
diff --git a/build.sc b/build.sc
index 814365ee..1afd55c4 100644
--- a/build.sc
+++ b/build.sc
@@ -45,7 +45,7 @@ trait CommonModule extends CrossSbtModule with PublishModule {
override def moduleDeps = super.moduleDeps ++ firrtlModule
override def ivyDeps = super.ivyDeps() ++ Agg(
- ivy"com.lihaoyi::os-lib:0.7.8",
+ ivy"com.lihaoyi::os-lib:0.8.0",
) ++ firrtlIvyDeps
def publishVersion = "3.5.0-RC2"
@@ -107,7 +107,7 @@ class chisel3CrossModule(val crossScalaVersion: String) extends CommonModule wit
override def scalacPluginClasspath = m.scalacPluginClasspath
override def ivyDeps = m.ivyDeps() ++ Agg(
- ivy"org.scalatest::scalatest:3.2.9",
+ ivy"org.scalatest::scalatest:3.2.10",
ivy"org.scalatestplus::scalacheck-1-14:3.2.2.0",
) ++ m.treadleIvyDeps
diff --git a/core/src/main/scala/chisel3/Aggregate.scala b/core/src/main/scala/chisel3/Aggregate.scala
index 17e46cb3..db354e1f 100644
--- a/core/src/main/scala/chisel3/Aggregate.scala
+++ b/core/src/main/scala/chisel3/Aggregate.scala
@@ -3,7 +3,7 @@
package chisel3
import chisel3.experimental.VecLiterals.AddVecLiteralConstructor
-import chisel3.experimental.dataview.{InvalidViewException, isView}
+import chisel3.experimental.dataview.{InvalidViewException, isView, reifySingleData}
import scala.collection.immutable.{SeqMap, VectorMap}
import scala.collection.mutable.{HashSet, LinkedHashMap}
@@ -29,7 +29,26 @@ sealed abstract class Aggregate extends Data {
val resolvedDirection = SpecifiedDirection.fromParent(parentDirection, specifiedDirection)
val duplicates = getElements.groupBy(identity).collect { case (x, elts) if elts.size > 1 => x }
if (!duplicates.isEmpty) {
- throw new AliasedAggregateFieldException(s"Aggregate $this contains aliased fields $duplicates")
+ this match {
+ case b: Record =>
+ // show groups of names of fields with duplicate id's
+ // The sorts make the displayed order of fields deterministic and matching the order of occurrence in the Bundle.
+ // It's a bit convoluted but happens rarely and makes the error message easier to understand
+ val dupNames = duplicates.toSeq.sortBy(_._id).map { duplicate =>
+ b.elements
+ .collect { case x if x._2._id == duplicate._id => x }
+ .toSeq.sortBy(_._2._id)
+ .map(_._1).reverse
+ .mkString("(", ",", ")")
+ }.mkString(",")
+ throw new AliasedAggregateFieldException(
+ s"${b.className} contains aliased fields named ${dupNames}"
+ )
+ case _ =>
+ throw new AliasedAggregateFieldException(
+ s"Aggregate ${this.getClass} contains aliased fields $duplicates ${duplicates.mkString(",")}"
+ )
+ }
}
for (child <- getElements) {
child.bind(ChildBinding(this), resolvedDirection)
@@ -54,7 +73,7 @@ sealed abstract class Aggregate extends Data {
override def litOption: Option[BigInt] = {
// Shift the accumulated value by our width and add in our component, masked by our width.
def shiftAdd(accumulator: Option[BigInt], elt: Data): Option[BigInt] = {
- (accumulator, elt.litOption()) match {
+ (accumulator, elt.litOption) match {
case (Some(accumulator), Some(eltLit)) =>
val width = elt.width.get
val masked = ((BigInt(1) << width) - 1) & eltLit // also handles the negative case with two's complement
@@ -164,16 +183,14 @@ sealed class Vec[T <: Data] private[chisel3] (gen: => T, val length: Int)
extends Aggregate with VecLike[T] {
override def toString: String = {
- val bindingString = topBindingOpt match {
+ topBindingOpt match {
case Some(VecLitBinding(vecLitBinding)) =>
val contents = vecLitBinding.zipWithIndex.map { case ((data, lit), index) =>
s"$index=$lit"
}.mkString(", ")
- s"($contents)"
- case _ => bindingToString
+ s"${sample_element.cloneType}[$length]($contents)"
+ case _ => stringAccessor(s"${sample_element.cloneType}[$length]")
}
- val elementType = sample_element.cloneType
- s"$elementType[$length]$bindingString"
}
private[chisel3] override def typeEquivalent(that: Data): Boolean = that match {
@@ -260,9 +277,20 @@ sealed class Vec[T <: Data] private[chisel3] (gen: => T, val length: Int)
def do_apply(p: UInt)(implicit compileOptions: CompileOptions): T = {
requireIsHardware(this, "vec")
requireIsHardware(p, "vec index")
+
+ // Special handling for views
if (isView(this)) {
- throw InvalidViewException("Dynamic indexing of Views is not yet supported")
+ reifySingleData(this) match {
+ // Views complicate things a bit, but views that correspond exactly to an identical Vec can just forward the
+ // dynamic indexing to the target Vec
+ // In theory, we could still do this forwarding if the sample element were different by deriving a DataView
+ case Some(target: Vec[T @unchecked]) if this.length == target.length &&
+ this.sample_element.typeEquivalent(target.sample_element) =>
+ return target.do_apply(p)
+ case _ => throw InvalidViewException("Dynamic indexing of Views is not yet supported")
+ }
}
+
val port = gen
// Reconstruct the resolvedDirection (in Aggregate.bind), since it's not stored.
@@ -329,11 +357,11 @@ sealed class Vec[T <: Data] private[chisel3] (gen: => T, val length: Int)
def do_reduceTree(redOp: (T, T) => T, layerOp: (T) => T = (x: T) => x)
(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions) : T = {
require(!isEmpty, "Cannot apply reduction on a vec of size 0")
- var curLayer = this
+ var curLayer : Seq[T] = this
while (curLayer.length > 1) {
- curLayer = VecInit(curLayer.grouped(2).map( x =>
+ curLayer = curLayer.grouped(2).map( x =>
if (x.length == 1) layerOp(x(0)) else redOp(x(0), x(1))
- ).toSeq)
+ ).toSeq
}
curLayer(0)
}
@@ -922,15 +950,14 @@ abstract class Record(private[chisel3] implicit val compileOptions: CompileOptio
* }}}
*/
override def toString: String = {
- val bindingString = topBindingOpt match {
+ topBindingOpt match {
case Some(BundleLitBinding(_)) =>
val contents = elements.toList.reverse.map { case (name, data) =>
s"$name=$data"
}.mkString(", ")
- s"($contents)"
- case _ => bindingToString
+ s"$className($contents)"
+ case _ => stringAccessor(s"$className")
}
- s"$className$bindingString"
}
def elements: SeqMap[String, Data]
@@ -1033,6 +1060,10 @@ package experimental {
* }}}
*/
abstract class Bundle(implicit compileOptions: CompileOptions) extends Record {
+ assert(_usingPlugin, "The Chisel compiler plugin is now required for compiling Chisel code. " +
+ "Please see https://github.com/chipsalliance/chisel3#build-your-own-chisel-projects."
+ )
+
override def className: String = this.getClass.getSimpleName match {
case name if name.startsWith("$anon$") => "AnonymousBundle" // fallback for anonymous Bundle case
case "" => "AnonymousBundle" // ditto, but on other platforms
@@ -1109,16 +1140,6 @@ abstract class Bundle(implicit compileOptions: CompileOptions) extends Record {
*/
protected def _usingPlugin: Boolean = false
- // Memoize the outer instance for autoclonetype, especially where this is context-dependent
- // (like the outer module or enclosing Bundles).
- private var _outerInst: Option[Object] = None
-
- // For reflective autoclonetype, record possible candidates for outer instance.
- // _outerInst should always take precedence, since it should be propagated from the original
- // object which has the most accurate context.
- private val _containingModule: Option[BaseModule] = if (_usingPlugin) None else Builder.currentModule
- private val _containingBundles: Seq[Bundle] = if (_usingPlugin) Nil else Builder.updateBundleStack(this)
-
private def checkClone(clone: Bundle): Unit = {
for ((name, field) <- elements) {
if (clone.elements(name) eq field) {
@@ -1142,220 +1163,10 @@ abstract class Bundle(implicit compileOptions: CompileOptions) extends Record {
/** Implementation of cloneType using runtime reflection. This should _never_ be overridden or called in user-code
*
- * @note This is overridden by the compiler plugin (it is never called when using the plugin)
+ * @note This is overridden by the compiler plugin (this implementation is never called)
*/
protected def _cloneTypeImpl: Bundle = {
- assert(Builder.allowReflectiveAutoCloneType, "reflective autoclonetype is disallowed, this should only happen in testing")
- // This attempts to infer constructor and arguments to clone this Bundle subtype without
- // requiring the user explicitly overriding cloneType.
- import scala.language.existentials
- import scala.reflect.runtime.universe._
-
- val clazz = this.getClass
-
- def autoClonetypeError(desc: String): Nothing =
- throw new AutoClonetypeException(
- s"Unable to automatically infer cloneType on $clazz. " +
- "cloneType is now implemented by the Chisel compiler plugin so please ensure you are using it in your build. " +
- "If you cannot use the compiler plugin or you are using it and you still see this message, please file an issue and let us know. " +
- s"For those not using the plugin, here is the 'runtime reflection' cloneType error message: $desc"
- )
-
- def validateClone(clone: Bundle, equivDiagnostic: String): Unit = {
- if (!clone.typeEquivalent(this)) {
- autoClonetypeError(s"Automatically cloned $clone not type-equivalent to base $this. " + equivDiagnostic)
- }
- checkClone(clone)
- }
-
- val mirror = runtimeMirror(clazz.getClassLoader)
-
- val classSymbolOption = try {
- Some(mirror.reflect(this).symbol)
- } catch {
- case e: scala.reflect.internal.Symbols#CyclicReference => None // Workaround for a scala bug
- }
-
- val enclosingClassOption = (clazz.getEnclosingClass, classSymbolOption) match {
- case (null, _) => None
- case (_, Some(classSymbol)) if classSymbol.isStatic => None // allows support for members of companion objects
- case (outerClass, _) => Some(outerClass)
- }
-
- // For compatibility with pre-3.1, where null is tried as an argument to the constructor.
- // This stores potential error messages which may be used later.
- var outerClassError: Option[String] = None
-
- // Check if this is an inner class, and if so, try to get the outer instance
- val outerClassInstance = enclosingClassOption.map { outerClass =>
- def canAssignOuterClass(x: Object) = outerClass.isAssignableFrom(x.getClass)
-
- val outerInstance = _outerInst match {
- case Some(outerInstance) => outerInstance // use _outerInst if defined
- case None => // determine outer instance if not already recorded
- try {
- // Prefer this if it works, but doesn't work in all cases, namely anonymous inner Bundles
- val outer = clazz.getDeclaredField("$outer").get(this)
- _outerInst = Some(outer)
- outer
- } catch {
- case (_: NoSuchFieldException | _: IllegalAccessException) =>
- // Fallback using guesses based on common patterns
- val allOuterCandidates = Seq(
- _containingModule.toSeq,
- _containingBundles
- ).flatten.distinct
- allOuterCandidates.filter(canAssignOuterClass(_)) match {
- case outer :: Nil =>
- _outerInst = Some(outer) // record the guess for future use
- outer
- case Nil => // TODO: replace with fatal autoClonetypeError once compatibility period is dropped
- outerClassError = Some(s"Unable to determine instance of outer class $outerClass," +
- s" no candidates assignable to outer class types; examined $allOuterCandidates")
- null
- case candidates => // TODO: replace with fatal autoClonetypeError once compatibility period is dropped
- outerClassError = Some(s"Unable to determine instance of outer class $outerClass," +
- s" multiple possible candidates $candidates assignable to outer class type")
- null
- }
- }
- }
- (outerClass, outerInstance)
- }
-
- // If possible (constructor with no arguments), try Java reflection first
- // This handles two cases that Scala reflection doesn't:
- // 1. getting the ClassSymbol of a class with an anonymous outer class fails with a
- // CyclicReference exception
- // 2. invoking the constructor of an anonymous inner class seems broken (it expects the outer
- // class as an argument, but fails because the number of arguments passed in is incorrect)
- if (clazz.getConstructors.size == 1) {
- var ctor = clazz.getConstructors.head
- val argTypes = ctor.getParameterTypes.toList
- val clone = (argTypes, outerClassInstance) match {
- case (Nil, None) => // no arguments, no outer class, invoke constructor directly
- Some(ctor.newInstance().asInstanceOf[this.type])
- case (argType :: Nil, Some((_, outerInstance))) =>
- if (outerInstance == null) {
- Builder.deprecated(s"chisel3.1 autoclonetype failed, falling back to 3.0 behavior using null as the outer instance." +
- s" Autoclonetype failure reason: ${outerClassError.get}",
- Some(s"$clazz"))
- Some(ctor.newInstance(outerInstance).asInstanceOf[this.type])
- } else if (argType isAssignableFrom outerInstance.getClass) {
- Some(ctor.newInstance(outerInstance).asInstanceOf[this.type])
- } else {
- None
- }
- case _ => None
-
- }
- clone match {
- case Some(clone) =>
- clone._outerInst = this._outerInst
- validateClone(clone, "Constructor argument values were not inferred, ensure constructor is deterministic.")
- return clone.asInstanceOf[this.type]
- case None =>
- }
- }
-
- // Get constructor parameters and accessible fields
- val classSymbol = classSymbolOption.getOrElse(autoClonetypeError(s"scala reflection failed." +
- " This is known to occur with inner classes on anonymous outer classes." +
- " In those cases, autoclonetype only works with no-argument constructors, or you can define a custom cloneType."))
-
- val decls = classSymbol.typeSignature.decls
- val ctors = decls.collect { case meth: MethodSymbol if meth.isConstructor => meth }
- if (ctors.size != 1) {
- autoClonetypeError(s"found multiple constructors ($ctors)." +
- " Either remove all but the default constructor, or define a custom cloneType method.")
- }
- val ctor = ctors.head
- val ctorParamss = ctor.paramLists
- val ctorParams = ctorParamss match {
- case Nil => List()
- case ctorParams :: Nil => ctorParams
- case ctorParams :: ctorImplicits :: Nil => ctorParams ++ ctorImplicits
- case _ => autoClonetypeError(s"internal error, unexpected ctorParamss = $ctorParamss")
- }
- val ctorParamsNames = ctorParams.map(_.name.toString)
-
- // Special case for anonymous inner classes: their constructor consists of just the outer class reference
- // Scala reflection on anonymous inner class constructors seems broken
- if (ctorParams.size == 1 && outerClassInstance.isDefined &&
- ctorParams.head.typeSignature == mirror.classSymbol(outerClassInstance.get._1).toType) {
- // Fall back onto Java reflection
- val ctors = clazz.getConstructors
- require(ctors.size == 1) // should be consistent with Scala constructors
- try {
- val clone = ctors.head.newInstance(outerClassInstance.get._2).asInstanceOf[this.type]
- clone._outerInst = this._outerInst
-
- validateClone(clone, "Outer class instance was inferred, ensure constructor is deterministic.")
- return clone
- } catch {
- case e @ (_: java.lang.reflect.InvocationTargetException | _: IllegalArgumentException) =>
- autoClonetypeError(s"unexpected failure at constructor invocation, got $e.")
- }
- }
-
- // Get all the class symbols up to (but not including) Bundle and get all the accessors.
- // (each ClassSymbol's decls only includes those declared in the class itself)
- val bundleClassSymbol = mirror.classSymbol(classOf[Bundle])
- val superClassSymbols = classSymbol.baseClasses.takeWhile(_ != bundleClassSymbol)
- val superClassDecls = superClassSymbols.map(_.typeSignature.decls).flatten
- val accessors = superClassDecls.collect { case meth: MethodSymbol if meth.isParamAccessor => meth }
-
- // Get constructor argument values
- // Check that all ctor params are immutable and accessible. Immutability is required to avoid
- // potential subtle bugs (like values changing after cloning).
- // This also generates better error messages (all missing elements shown at once) instead of
- // failing at the use site one at a time.
- val accessorsName = accessors.filter(_.isStable).map(_.name.toString)
- val paramsDiff = ctorParamsNames.toSet -- accessorsName.toSet
- if (!paramsDiff.isEmpty) {
- autoClonetypeError(s"constructor has parameters (${paramsDiff.toList.sorted.mkString(", ")}) that are not both immutable and accessible." +
- " Either make all parameters immutable and accessible (vals) so cloneType can be inferred, or define a custom cloneType method.")
- }
-
- // Get all the argument values
- val accessorsMap = accessors.map(accessor => accessor.name.toString -> accessor).toMap
- val instanceReflect = mirror.reflect(this)
- val ctorParamsNameVals = ctorParamsNames.map {
- paramName => paramName -> instanceReflect.reflectMethod(accessorsMap(paramName)).apply()
- }
-
- // Opportunistic sanity check: ensure any arguments of type Data is not bound
- // (which could lead to data conflicts, since it's likely the user didn't know to re-bind them).
- // This is not guaranteed to catch all cases (for example, Data in Tuples or Iterables).
- val boundDataParamNames = ctorParamsNameVals.collect {
- case (paramName, paramVal: Data) if paramVal.topBindingOpt.isDefined => paramName
- }
- if (boundDataParamNames.nonEmpty) {
- autoClonetypeError(s"constructor parameters (${boundDataParamNames.sorted.mkString(", ")}) have values that are hardware types, which is likely to cause subtle errors." +
- " Use chisel types instead: use the value before it is turned to a hardware type (with Wire(...), Reg(...), etc) or use chiselTypeOf(...) to extract the chisel type.")
- }
-
- // Clone unbound parameters in case they are being used as bundle fields.
- val ctorParamsVals = ctorParamsNameVals.map {
- case (_, paramVal: Data) => paramVal.cloneTypeFull
- case (_, paramVal) => paramVal
- }
-
- // Invoke ctor
- val classMirror = outerClassInstance match {
- case Some((_, null)) => autoClonetypeError(outerClassError.get) // deals with the null hack for 3.0 compatibility
- case Some((_, outerInstance)) => mirror.reflect(outerInstance).reflectClass(classSymbol)
- case _ => mirror.reflectClass(classSymbol)
- }
- val clone = classMirror.reflectConstructor(ctor).apply(ctorParamsVals:_*).asInstanceOf[this.type]
- clone._outerInst = this._outerInst
-
- validateClone(clone,
- "Constructor argument values were inferred:" +
- " ensure that variable names are consistent and have the same value throughout the constructor chain," +
- " and that the constructor is deterministic."
- )
- clone
+ throwException(s"Internal Error! This should have been implemented by the chisel3-plugin. Please file an issue against chisel3")
}
/** Default "pretty-print" implementation
diff --git a/core/src/main/scala/chisel3/Assert.scala b/core/src/main/scala/chisel3/Assert.scala
deleted file mode 100644
index 9a497e1f..00000000
--- a/core/src/main/scala/chisel3/Assert.scala
+++ /dev/null
@@ -1,92 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-
-package chisel3
-
-import scala.reflect.macros.blackbox.Context
-import scala.language.experimental.macros
-
-import chisel3.internal._
-import chisel3.internal.Builder.pushCommand
-import chisel3.internal.firrtl._
-import chisel3.internal.sourceinfo.SourceInfo
-
-object assert {
- /** Checks for a condition to be valid in the circuit at all times. If the
- * condition evaluates to false, the circuit simulation stops with an error.
- *
- * Does not fire when in reset (defined as the encapsulating Module's
- * reset). If your definition of reset is not the encapsulating Module's
- * reset, you will need to gate this externally.
- *
- * May be called outside of a Module (like defined in a function), so
- * functions using assert make the standard Module assumptions (single clock
- * and single reset).
- *
- * @param cond condition, assertion fires (simulation fails) when false
- * @param message optional format string to print when the assertion fires
- * @param data optional bits to print in the message formatting
- *
- * @note See [[printf.apply(fmt:String* printf]] for format string documentation
- * @note currently cannot be used in core Chisel / libraries because macro
- * defs need to be compiled first and the SBT project is not set up to do
- * that
- */
- // Macros currently can't take default arguments, so we need two functions to emulate defaults.
- def apply(cond: Bool, message: String, data: Bits*)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Unit = macro apply_impl_msg_data
- def apply(cond: Bool)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Unit = macro apply_impl
-
- def apply_impl_msg_data(c: Context)(cond: c.Tree, message: c.Tree, data: c.Tree*)(sourceInfo: c.Tree, compileOptions: c.Tree): c.Tree = {
- import c.universe._
- val p = c.enclosingPosition
- val condStr = s"${p.source.file.name}:${p.line} ${p.lineContent.trim}"
- val apply_impl_do = symbolOf[this.type].asClass.module.info.member(TermName("apply_impl_do"))
- q"$apply_impl_do($cond, $condStr, _root_.scala.Some($message), ..$data)($sourceInfo, $compileOptions)"
- }
-
- def apply_impl(c: Context)(cond: c.Tree)(sourceInfo: c.Tree, compileOptions: c.Tree): c.Tree = {
- import c.universe._
- val p = c.enclosingPosition
- val condStr = s"${p.source.file.name}:${p.line} ${p.lineContent.trim}"
- val apply_impl_do = symbolOf[this.type].asClass.module.info.member(TermName("apply_impl_do"))
- q"$apply_impl_do($cond, $condStr, _root_.scala.None)($sourceInfo, $compileOptions)"
- }
-
- def apply_impl_do(cond: Bool, line: String, message: Option[String], data: Bits*)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions) {
- val escLine = line.replaceAll("%", "%%")
- when (!(cond || Module.reset.asBool)) {
- val fmt = message match {
- case Some(msg) =>
- s"Assertion failed: $msg\n at $escLine\n"
- case None => s"Assertion failed\n at $escLine\n"
- }
- printf.printfWithoutReset(fmt, data:_*)
- pushCommand(Stop(sourceInfo, Builder.forcedClock.ref, 1))
- }
- }
-
- /** An elaboration-time assertion, otherwise the same as the above run-time
- * assertion. */
- def apply(cond: Boolean, message: => String) {
- Predef.assert(cond, message)
- }
-
- /** A workaround for default-value overloading problems in Scala, just
- * 'assert(cond, "")' */
- def apply(cond: Boolean) {
- Predef.assert(cond, "")
- }
-}
-
-object stop {
- /** Terminate execution with a failure code. */
- def apply(code: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Unit = {
- when (!Module.reset.asBool) {
- pushCommand(Stop(sourceInfo, Builder.forcedClock.ref, code))
- }
- }
-
- /** Terminate execution, indicating success. */
- def apply()(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Unit = {
- stop(0)
- }
-}
diff --git a/core/src/main/scala/chisel3/Bits.scala b/core/src/main/scala/chisel3/Bits.scala
index 670f6e7a..5ab04d13 100644
--- a/core/src/main/scala/chisel3/Bits.scala
+++ b/core/src/main/scala/chisel3/Bits.scala
@@ -25,7 +25,10 @@ private[chisel3] sealed trait ToBoolable extends Element {
*
* @note The width must be known and equal to 1
*/
- final def asBool(): Bool = macro SourceInfoWhiteboxTransform.noArg
+ final def asBool: Bool = macro SourceInfoWhiteboxTransform.noArg
+
+ @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5")
+ final def asBool(dummy: Int*): Bool = macro SourceInfoWhiteboxTransform.noArgDummy
/** @group SourceInfoTransformMacro */
def do_asBool(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool
@@ -222,7 +225,10 @@ sealed abstract class Bits(private[chisel3] val width: Width) extends Element wi
* @return this $coll with each bit inverted
* @group Bitwise
*/
- final def unary_~ (): Bits = macro SourceInfoWhiteboxTransform.noArg
+ final def unary_~ : Bits = macro SourceInfoWhiteboxTransform.noArg
+
+ @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5")
+ final def unary_~(dummy: Int*): Bits = macro SourceInfoWhiteboxTransform.noArgDummy
/** @group SourceInfoTransformMacro */
def do_unary_~ (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bits
@@ -304,10 +310,10 @@ sealed abstract class Bits(private[chisel3] val width: Width) extends Element wi
def do_>> (that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bits
/** Returns the contents of this wire as a [[scala.collection.Seq]] of [[Bool]]. */
- final def toBools(): Seq[Bool] = macro SourceInfoTransform.noArg
+ final def asBools: Seq[Bool] = macro SourceInfoTransform.noArg
- /** Returns the contents of this wire as a [[scala.collection.Seq]] of [[Bool]]. */
- final def asBools(): Seq[Bool] = macro SourceInfoTransform.noArg
+ @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5")
+ final def asBools(dummy: Int*): Seq[Bool] = macro SourceInfoWhiteboxTransform.noArgDummy
/** @group SourceInfoTransformMacro */
def do_asBools(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Seq[Bool] =
@@ -318,7 +324,10 @@ sealed abstract class Bits(private[chisel3] val width: Width) extends Element wi
* @note The arithmetic value is not preserved if the most-significant bit is set. For example, a [[UInt]] of
* width 3 and value 7 (0b111) would become an [[SInt]] of width 3 and value -1.
*/
- final def asSInt(): SInt = macro SourceInfoTransform.noArg
+ final def asSInt: SInt = macro SourceInfoTransform.noArg
+
+ @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5")
+ final def asSInt(dummy: Int*): SInt = macro SourceInfoWhiteboxTransform.noArgDummy
/** @group SourceInfoTransformMacro */
def do_asSInt(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt
@@ -390,11 +399,10 @@ sealed abstract class Bits(private[chisel3] val width: Width) extends Element wi
*/
sealed class UInt private[chisel3] (width: Width) extends Bits(width) with Num[UInt] {
override def toString: String = {
- val bindingString = litOption match {
- case Some(value) => s"($value)"
- case _ => bindingToString
+ litOption match {
+ case Some(value) => s"UInt$width($value)"
+ case _ => stringAccessor(s"UInt$width")
}
- s"UInt$width$bindingString"
}
private[chisel3] override def typeEquivalent(that: Data): Boolean =
@@ -410,7 +418,10 @@ sealed class UInt private[chisel3] (width: Width) extends Bits(width) with Num[U
* $constantWidth
* @group Arithmetic
*/
- final def unary_- (): UInt = macro SourceInfoTransform.noArg
+ final def unary_- : UInt = macro SourceInfoTransform.noArg
+
+ @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5")
+ final def unary_-(dummy: Int*): UInt = macro SourceInfoTransform.noArgDummy
/** Unary negation (constant width)
*
@@ -418,7 +429,10 @@ sealed class UInt private[chisel3] (width: Width) extends Bits(width) with Num[U
* $constantWidth
* @group Arithmetic
*/
- final def unary_-% (): UInt = macro SourceInfoTransform.noArg
+ final def unary_-% : UInt = macro SourceInfoTransform.noArg
+
+ @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5")
+ final def unary_%(dummy: Int*): UInt = macro SourceInfoTransform.noArgDummy
/** @group SourceInfoTransformMacro */
def do_unary_- (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions) : UInt = 0.U - this
@@ -522,7 +536,7 @@ sealed class UInt private[chisel3] (width: Width) extends Bits(width) with Num[U
*/
final def ^ (that: UInt): UInt = macro SourceInfoTransform.thatArg
- // override def abs: UInt = macro SourceInfoTransform.noArg
+ // override def abs: UInt = macro SourceInfoTransform.noArgDummy
def do_abs(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = this
/** @group SourceInfoTransformMacro */
@@ -545,21 +559,30 @@ sealed class UInt private[chisel3] (width: Width) extends Bits(width) with Num[U
* @return a hardware [[Bool]] resulting from every bit of this $coll or'd together
* @group Bitwise
*/
- final def orR(): Bool = macro SourceInfoTransform.noArg
+ final def orR: Bool = macro SourceInfoTransform.noArg
+
+ @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5")
+ final def orR(dummy: Int*): Bool = macro SourceInfoTransform.noArgDummy
/** And reduction operator
*
* @return a hardware [[Bool]] resulting from every bit of this $coll and'd together
* @group Bitwise
*/
- final def andR(): Bool = macro SourceInfoTransform.noArg
+ final def andR: Bool = macro SourceInfoTransform.noArg
+
+ @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5")
+ final def andR(dummy: Int*): Bool = macro SourceInfoTransform.noArgDummy
/** Exclusive or (xor) reduction operator
*
* @return a hardware [[Bool]] resulting from every bit of this $coll xor'd together
* @group Bitwise
*/
- final def xorR(): Bool = macro SourceInfoTransform.noArg
+ final def xorR: Bool = macro SourceInfoTransform.noArg
+
+ @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5")
+ final def xorR(dummy: Int*): Bool = macro SourceInfoTransform.noArgDummy
/** @group SourceInfoTransformMacro */
def do_orR(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = redop(sourceInfo, OrReduceOp)
@@ -599,7 +622,10 @@ sealed class UInt private[chisel3] (width: Width) extends Bits(width) with Num[U
* @return a hardware [[Bool]] asserted if this $coll equals zero
* @group Bitwise
*/
- final def unary_! () : Bool = macro SourceInfoTransform.noArg
+ final def unary_! : Bool = macro SourceInfoTransform.noArg
+
+ @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5")
+ final def unary_! (dummy: Int*): Bool = macro SourceInfoTransform.noArgDummy
/** @group SourceInfoTransformMacro */
def do_unary_! (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions) : Bool = this === 0.U(1.W)
@@ -617,6 +643,51 @@ sealed class UInt private[chisel3] (width: Width) extends Bits(width) with Num[U
override def do_>> (that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt =
binop(sourceInfo, UInt(this.width), DynamicShiftRightOp, that)
+ /**
+ * Circular shift to the left
+ * @param that number of bits to rotate
+ * @return UInt of same width rotated left n bits
+ */
+ final def rotateLeft(that: Int): UInt = macro SourceInfoWhiteboxTransform.thatArg
+
+ def do_rotateLeft(n: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = width match {
+ case _ if (n == 0) => this
+ case KnownWidth(w) if (w <= 1) => this
+ case KnownWidth(w) if n >= w => do_rotateLeft(n % w)
+ case _ if (n < 0) => do_rotateRight(-n)
+ case _ => tail(n) ## head(n)
+ }
+
+ /**
+ * Circular shift to the right
+ * @param that number of bits to rotate
+ * @return UInt of same width rotated right n bits
+ */
+ final def rotateRight(that: Int): UInt = macro SourceInfoWhiteboxTransform.thatArg
+
+ def do_rotateRight(n: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt = width match {
+ case _ if (n <= 0) => do_rotateLeft(-n)
+ case KnownWidth(w) if (w <= 1) => this
+ case KnownWidth(w) if n >= w => do_rotateRight(n % w)
+ case _ => this(n - 1, 0) ## (this >> n)
+ }
+
+ final def rotateRight(that: UInt): UInt = macro SourceInfoWhiteboxTransform.thatArg
+
+ private def dynamicShift(n: UInt, staticShift: (UInt,Int) => UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions) : UInt =
+ n.asBools().zipWithIndex.foldLeft(this){
+ case (in, (en, sh)) => Mux(en, staticShift(in, 1 << sh), in)
+ }
+
+ def do_rotateRight(n: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt =
+ dynamicShift(n, _ rotateRight _)
+
+ final def rotateLeft(that: UInt): UInt = macro SourceInfoWhiteboxTransform.thatArg
+
+ def do_rotateLeft(n: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt =
+ dynamicShift(n, _ rotateLeft _)
+
+
/** Conditionally set or clear a bit
*
* @param off a dynamic offset
@@ -639,7 +710,11 @@ sealed class UInt private[chisel3] (width: Width) extends Bits(width) with Num[U
* @return an [[SInt]] equal to this $coll with an additional zero in its most significant bit
* @note The width of the returned [[SInt]] is `width of this` + `1`.
*/
- final def zext(): SInt = macro SourceInfoTransform.noArg
+ final def zext: SInt = macro SourceInfoTransform.noArg
+
+ @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5")
+ final def zext(dummy: Int*): SInt = macro SourceInfoTransform.noArgDummy
+
/** @group SourceInfoTransformMacro */
def do_zext(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt =
pushOp(DefPrim(sourceInfo, SInt(width + 1), ConvertOp, ref))
@@ -697,11 +772,10 @@ sealed class UInt private[chisel3] (width: Width) extends Bits(width) with Num[U
*/
sealed class SInt private[chisel3] (width: Width) extends Bits(width) with Num[SInt] {
override def toString: String = {
- val bindingString = litOption match {
- case Some(value) => s"($value)"
- case _ => bindingToString
+ litOption match {
+ case Some(value) => s"SInt$width($value)"
+ case _ => stringAccessor(s"SInt$width")
}
- s"SInt$width$bindingString"
}
private[chisel3] override def typeEquivalent(that: Data): Boolean =
@@ -716,7 +790,10 @@ sealed class SInt private[chisel3] (width: Width) extends Bits(width) with Num[S
* $constantWidth
* @group Arithmetic
*/
- final def unary_- (): SInt = macro SourceInfoTransform.noArg
+ final def unary_- : SInt = macro SourceInfoTransform.noArg
+
+ @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5")
+ final def unary_-(dummy: Int*): SInt = macro SourceInfoTransform.noArgDummy
/** Unary negation (constant width)
*
@@ -724,12 +801,15 @@ sealed class SInt private[chisel3] (width: Width) extends Bits(width) with Num[S
* $constantWidth
* @group Arithmetic
*/
- final def unary_-% (): SInt = macro SourceInfoTransform.noArg
+ final def unary_-% : SInt = macro SourceInfoTransform.noArg
+
+ @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5")
+ final def unary_-%(dummy: Int*): SInt = macro SourceInfoTransform.noArgDummy
/** @group SourceInfoTransformMacro */
- def unary_- (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt = 0.S - this
+ def do_unary_- (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt = 0.S - this
/** @group SourceInfoTransformMacro */
- def unary_-% (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt = 0.S -% this
+ def do_unary_-% (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt = 0.S -% this
/** add (default - no growth) operator */
override def do_+ (that: SInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt =
@@ -755,7 +835,7 @@ sealed class SInt private[chisel3] (width: Width) extends Bits(width) with Num[S
final def * (that: UInt): SInt = macro SourceInfoTransform.thatArg
/** @group SourceInfoTransformMacro */
def do_* (that: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt = {
- val thatToSInt = that.zext()
+ val thatToSInt = that.zext
val result = binop(sourceInfo, SInt(this.width + thatToSInt.width), TimesOp, thatToSInt)
result.tail(1).asSInt
}
@@ -876,10 +956,10 @@ sealed class SInt private[chisel3] (width: Width) extends Bits(width) with Num[S
/** @group SourceInfoTransformMacro */
def do_=== (that: SInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = compop(sourceInfo, EqualOp, that)
-// final def abs(): UInt = macro SourceInfoTransform.noArg
+// final def abs(): UInt = macro SourceInfoTransform.noArgDummy
def do_abs(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt = {
- Mux(this < 0.S, (-this), this)
+ Mux(this < 0.S, -this, this)
}
override def do_<< (that: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): SInt =
@@ -938,7 +1018,10 @@ sealed class SInt private[chisel3] (width: Width) extends Bits(width) with Num[S
sealed trait Reset extends Element with ToBoolable {
/** Casts this $coll to an [[AsyncReset]] */
- final def asAsyncReset(): AsyncReset = macro SourceInfoWhiteboxTransform.noArg
+ final def asAsyncReset: AsyncReset = macro SourceInfoWhiteboxTransform.noArg
+
+ @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5")
+ final def asAsyncReset(dummy: Int*): AsyncReset = macro SourceInfoTransform.noArgDummy
/** @group SourceInfoTransformMacro */
def do_asAsyncReset(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): AsyncReset
@@ -954,7 +1037,7 @@ object Reset {
* super type due to Bool inheriting from abstract class UInt
*/
final class ResetType(private[chisel3] val width: Width = Width(1)) extends Element with Reset {
- override def toString: String = s"Reset$bindingToString"
+ override def toString: String = stringAccessor("Reset")
def cloneType: this.type = Reset().asInstanceOf[this.type]
@@ -996,7 +1079,7 @@ object AsyncReset {
* asychronously reset registers.
*/
sealed class AsyncReset(private[chisel3] val width: Width = Width(1)) extends Element with Reset {
- override def toString: String = s"AsyncReset$bindingToString"
+ override def toString: String = stringAccessor("AsyncReset")
def cloneType: this.type = AsyncReset().asInstanceOf[this.type]
@@ -1036,11 +1119,10 @@ sealed class AsyncReset(private[chisel3] val width: Width = Width(1)) extends El
*/
sealed class Bool() extends UInt(1.W) with Reset {
override def toString: String = {
- val bindingString = litToBooleanOption match {
- case Some(value) => s"($value)"
- case _ => bindingToString
+ litToBooleanOption match {
+ case Some(value) => s"Bool($value)"
+ case _ => stringAccessor("Bool")
}
- s"Bool$bindingString"
}
private[chisel3] override def cloneTypeWidth(w: Width): this.type = {
@@ -1124,7 +1206,10 @@ sealed class Bool() extends UInt(1.W) with Reset {
def do_&& (that: Bool)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = this & that
/** Reinterprets this $coll as a clock */
- def asClock(): Clock = macro SourceInfoTransform.noArg
+ def asClock: Clock = macro SourceInfoTransform.noArg
+
+ @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5")
+ def asClock(dummy: Int*): Clock = macro SourceInfoTransform.noArgDummy
/** @group SourceInfoTransformMacro */
def do_asClock(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Clock = pushOp(DefPrim(sourceInfo, Clock(), AsClockOp, ref))
@@ -1194,11 +1279,10 @@ package experimental {
extends Bits(width) with Num[FixedPoint] with HasBinaryPoint {
override def toString: String = {
- val bindingString = litToDoubleOption match {
- case Some(value) => s"($value)"
- case _ => bindingToString
+ litToDoubleOption match {
+ case Some(value) => s"FixedPoint$width$binaryPoint($value)"
+ case _ => stringAccessor(s"FixedPoint$width$binaryPoint")
}
- s"FixedPoint$width$binaryPoint$bindingString"
}
private[chisel3] override def typeEquivalent(that: Data): Boolean = that match {
@@ -1220,7 +1304,10 @@ package experimental {
* $expandingWidth
* @group Arithmetic
*/
- final def unary_- (): FixedPoint = macro SourceInfoTransform.noArg
+ final def unary_- : FixedPoint = macro SourceInfoTransform.noArg
+
+ @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5")
+ final def unary_-(dummy: Int*): FixedPoint = macro SourceInfoTransform.noArgDummy
/** Unary negation (constant width)
*
@@ -1228,12 +1315,14 @@ package experimental {
* $constantWidth
* @group Arithmetic
*/
- final def unary_-% (): FixedPoint = macro SourceInfoTransform.noArg
+ final def unary_-% : FixedPoint = macro SourceInfoTransform.noArg
+ @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5")
+ final def unary_-%(dummy: Int*): FixedPoint = macro SourceInfoTransform.noArgDummy
/** @group SourceInfoTransformMacro */
- def unary_- (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = FixedPoint.fromBigInt(0) - this
+ def do_unary_- (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = FixedPoint.fromBigInt(0) - this
/** @group SourceInfoTransformMacro */
- def unary_-% (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = FixedPoint.fromBigInt(0) -% this
+ def do_unary_-% (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint = FixedPoint.fromBigInt(0) -% this
/** add (default - no growth) operator */
override def do_+ (that: FixedPoint)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): FixedPoint =
@@ -1609,11 +1698,10 @@ package experimental {
extends Bits(range.getWidth) with Num[Interval] with HasBinaryPoint {
override def toString: String = {
- val bindingString = litOption match {
- case Some(value) => s"($value)"
- case _ => bindingToString
+ litOption match {
+ case Some(value) => s"Interval$width($value)"
+ case _ => stringAccessor(s"Interval$width")
}
- s"Interval$width$bindingString"
}
private[chisel3] override def cloneTypeWidth(w: Width): this.type =
@@ -1663,13 +1751,21 @@ package experimental {
}
}
- final def unary_-(): Interval = macro SourceInfoTransform.noArg
- final def unary_-%(): Interval = macro SourceInfoTransform.noArg
+ final def unary_- : Interval = macro SourceInfoTransform.noArg
- def unary_-(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = {
+ @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5")
+ final def unary_-(dummy: Int*): Interval = macro SourceInfoTransform.noArgDummy
+
+ final def unary_-% : Interval = macro SourceInfoTransform.noArg
+
+ @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5")
+ final def unary_-%(dummy: Int*): Interval = macro SourceInfoTransform.noArgDummy
+
+ /** @group SourceInfoTransformMacro */
+ def do_unary_-(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = {
Interval.Zero - this
}
- def unary_-%(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = {
+ def do_unary_-%(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = {
Interval.Zero -% this
}
@@ -1779,7 +1875,7 @@ package experimental {
def do_=/= (that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = compop(sourceInfo, NotEqualOp, that)
def do_=== (that: Interval)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = compop(sourceInfo, EqualOp, that)
- // final def abs(): UInt = macro SourceInfoTransform.noArg
+ // final def abs(): UInt = macro SourceInfoTransform.noArgDummy
def do_abs(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Interval = {
Mux(this < Interval.Zero, (Interval.Zero - this), this)
diff --git a/core/src/main/scala/chisel3/BlackBox.scala b/core/src/main/scala/chisel3/BlackBox.scala
index 38b08193..ec5de0cd 100644
--- a/core/src/main/scala/chisel3/BlackBox.scala
+++ b/core/src/main/scala/chisel3/BlackBox.scala
@@ -8,6 +8,7 @@ import chisel3.internal.Builder.pushCommand
import chisel3.internal.firrtl._
import chisel3.internal.throwException
import chisel3.internal.sourceinfo.{SourceInfo, UnlocatableSourceInfo}
+import scala.annotation.nowarn
package internal {
@@ -61,6 +62,7 @@ package experimental {
* }}}
* @note The parameters API is experimental and may change
*/
+ @nowarn("msg=class Port") // delete when Port becomes private
abstract class ExtModule(val params: Map[String, Param] = Map.empty[String, Param]) extends BaseBlackBox {
private[chisel3] override def generateComponent(): Option[Component] = {
require(!_closed, "Can't generate module more than once")
@@ -134,6 +136,7 @@ package experimental {
* }}}
* @note The parameters API is experimental and may change
*/
+@nowarn("msg=class Port") // delete when Port becomes private
abstract class BlackBox(val params: Map[String, Param] = Map.empty[String, Param])(implicit compileOptions: CompileOptions) extends BaseBlackBox {
// Find a Record port named "io" for purposes of stripping the prefix
diff --git a/core/src/main/scala/chisel3/Clock.scala b/core/src/main/scala/chisel3/Clock.scala
index edb07908..e4be6558 100644
--- a/core/src/main/scala/chisel3/Clock.scala
+++ b/core/src/main/scala/chisel3/Clock.scala
@@ -14,7 +14,7 @@ object Clock {
// TODO: Document this.
sealed class Clock(private[chisel3] val width: Width = Width(1)) extends Element {
- override def toString: String = s"Clock$bindingToString"
+ override def toString: String = stringAccessor("Clock")
def cloneType: this.type = Clock().asInstanceOf[this.type]
@@ -32,8 +32,12 @@ sealed class Clock(private[chisel3] val width: Width = Width(1)) extends Element
def toPrintable: Printable = PString("CLOCK")
/** Returns the contents of the clock wire as a [[Bool]]. */
- final def asBool(): Bool = macro SourceInfoTransform.noArg
- def do_asBool(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = this.asUInt().asBool()
+ final def asBool: Bool = macro SourceInfoTransform.noArg
+
+ @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5")
+ final def asBool(dummy: Int*): Bool = macro SourceInfoTransform.noArgDummy
+
+ def do_asBool(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = this.asUInt.asBool
override def do_asUInt(implicit sourceInfo: SourceInfo, connectCompileOptions: CompileOptions): UInt = pushOp(DefPrim(sourceInfo, UInt(this.width), AsUIntOp, ref))
private[chisel3] override def connectFromBits(that: Bits)(implicit sourceInfo: SourceInfo,
diff --git a/core/src/main/scala/chisel3/Data.scala b/core/src/main/scala/chisel3/Data.scala
index 32d83008..2bca5f98 100644
--- a/core/src/main/scala/chisel3/Data.scala
+++ b/core/src/main/scala/chisel3/Data.scala
@@ -154,13 +154,58 @@ package experimental {
**/
def checkTypeEquivalence(x: Data, y: Data): Boolean = x.typeEquivalent(y)
- // Returns the top-level module ports
- // TODO: maybe move to something like Driver or DriverUtils, since this is mainly for interacting
- // with compiled artifacts (vs. elaboration-time reflection)?
+ /** Returns the ports of a module
+ * {{{
+ * class MyModule extends Module {
+ * val io = IO(new Bundle {
+ * val in = Input(UInt(8.W))
+ * val out = Output(Vec(2, UInt(8.W)))
+ * })
+ * val extra = IO(Input(UInt(8.W)))
+ * val delay = RegNext(io.in)
+ * io.out(0) := delay
+ * io.out(1) := delay + extra
+ * }
+ * val mod = Module(new MyModule)
+ * DataMirror.modulePorts(mod)
+ * // returns: Seq(
+ * // "clock" -> mod.clock,
+ * // "reset" -> mod.reset,
+ * // "io" -> mod.io,
+ * // "extra" -> mod.extra
+ * // )
+ * }}}
+ */
def modulePorts(target: BaseModule): Seq[(String, Data)] = target.getChiselPorts
- /** Returns all module ports with underscore-qualified names
- * return includes [[Module.clock]] and [[Module.reset]]
+ /** Returns a recursive representation of a module's ports with underscore-qualified names
+ * {{{
+ * class MyModule extends Module {
+ * val io = IO(new Bundle {
+ * val in = Input(UInt(8.W))
+ * val out = Output(Vec(2, UInt(8.W)))
+ * })
+ * val extra = IO(Input(UInt(8.W)))
+ * val delay = RegNext(io.in)
+ * io.out(0) := delay
+ * io.out(1) := delay + extra
+ * }
+ * val mod = Module(new MyModule)
+ * DataMirror.fullModulePorts(mod)
+ * // returns: Seq(
+ * // "clock" -> mod.clock,
+ * // "reset" -> mod.reset,
+ * // "io" -> mod.io,
+ * // "io_out" -> mod.io.out,
+ * // "io_out_0" -> mod.io.out(0),
+ * // "io_out_1" -> mod.io.out(1),
+ * // "io_in" -> mod.io.in,
+ * // "extra" -> mod.extra
+ * // )
+ * }}}
+ * @note The returned ports are redundant. An [[Aggregate]] port will be present along with all
+ * of its children.
+ * @see [[DataMirror.modulePorts]] for a non-recursive representation of the ports.
*/
def fullModulePorts(target: BaseModule): Seq[(String, Data)] = {
def getPortNames(name: String, data: Data): Seq[(String, Data)] = Seq(name -> data) ++ (data match {
@@ -435,27 +480,44 @@ abstract class Data extends HasId with NamedComponent with SourceInfoDoc {
_direction = Some(actualDirection)
}
+ private[chisel3] def stringAccessor(chiselType: String): String = {
+ topBindingOpt match {
+ case None => chiselType
+ // Handle DontCares specially as they are "literal-like" but not actually literals
+ case Some(DontCareBinding()) => s"$chiselType(DontCare)"
+ case Some(topBinding) =>
+ val binding: String = _bindingToString(topBinding)
+ val name = earlyName
+ val mod = parentNameOpt.map(_ + ".").getOrElse("")
+
+ s"$mod$name: $binding[$chiselType]"
+ }
+ }
+
// 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 = Try(topBindingOpt match {
- case None => ""
- case Some(OpBinding(enclosure, _)) => s"(OpResult in ${enclosure.desiredName})"
- case Some(MemoryPortBinding(enclosure, _)) => s"(MemPort in ${enclosure.desiredName})"
- case Some(PortBinding(enclosure)) if !enclosure.isClosed => s"(IO in unelaborated ${enclosure.desiredName})"
- case Some(PortBinding(enclosure)) if enclosure.isClosed =>
- DataMirror.fullModulePorts(enclosure).find(_._2 eq this) match {
- case Some((name, _)) => s"(IO $name in ${enclosure.desiredName})"
- case None => s"(IO (unknown) in ${enclosure.desiredName})"
- }
- case Some(RegBinding(enclosure, _)) => s"(Reg in ${enclosure.desiredName})"
- case Some(WireBinding(enclosure, _)) => s"(Wire in ${enclosure.desiredName})"
- case Some(DontCareBinding()) => s"(DontCare)"
- case Some(ElementLitBinding(litArg)) => s"(unhandled literal)"
- case Some(BundleLitBinding(litMap)) => s"(unhandled bundle literal)"
- case Some(VecLitBinding(litMap)) => s"(unhandled vec literal)"
- }).getOrElse("")
+ @deprecated("This was never intended to be visible to user-defined types", "Chisel 3.5.0")
+ protected def bindingToString: String = _bindingToString(topBinding)
+
+ private[chisel3] def _bindingToString(topBindingOpt: TopBinding): String =
+ topBindingOpt match {
+ case OpBinding(_, _) => "OpResult"
+ case MemoryPortBinding(_, _) => "MemPort"
+ case PortBinding(_) => "IO"
+ case RegBinding(_, _) => "Reg"
+ case WireBinding(_, _) => "Wire"
+ case DontCareBinding() => "(DontCare)"
+ case ElementLitBinding(litArg) => "(unhandled literal)"
+ case BundleLitBinding(litMap) => "(unhandled bundle literal)"
+ case VecLitBinding(litMap) => "(unhandled vec literal)"
+ case _ => ""
+ }
+
+ private[chisel3] def earlyName: String = Arg.earlyLocalName(this)
+
+ private[chisel3] def parentNameOpt: Option[String] = this._parent.map(_.name)
// Return ALL elements at root of this type.
// Contasts with flatten, which returns just Bits
@@ -477,7 +539,7 @@ abstract class Data extends HasId with NamedComponent with SourceInfoDoc {
} catch {
case MonoConnectException(message) =>
throwException(
- s"Connection between sink ($this) and source ($that) failed @$message"
+ s"Connection between sink ($this) and source ($that) failed @: $message"
)
}
} else {
@@ -645,18 +707,28 @@ abstract class Data extends HasId with NamedComponent with SourceInfoDoc {
}
}
- def isLit(): Boolean = litOption.isDefined
+ def isLit: Boolean = litOption.isDefined
+
+ @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5")
+ def isLit(dummy: Int*): Boolean = isLit
+
/**
* If this is a literal that is representable as bits, returns the value as a BigInt.
* If not a literal, or not representable as bits (for example, is or contains Analog), returns None.
*/
- def litOption(): Option[BigInt]
+ def litOption: Option[BigInt]
+
+ @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5")
+ def litOption(dummy: Int*): Option[BigInt] = litOption
/**
* Returns the literal value if this is a literal that is representable as bits, otherwise crashes.
*/
- def litValue(): BigInt = litOption.get
+ def litValue: BigInt = litOption.get
+
+ @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5")
+ def litValue(dummy: Int*): BigInt = litValue
/** Returns the width, in bits, if currently known. */
final def getWidth: Int =
@@ -679,7 +751,7 @@ abstract class Data extends HasId with NamedComponent with SourceInfoDoc {
/** @group SourceInfoTransformMacro */
def do_asTypeOf[T <: Data](that: T)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = {
val thatCloned = Wire(that.cloneTypeFull)
- thatCloned.connectFromBits(this.asUInt())
+ thatCloned.connectFromBits(this.asUInt)
thatCloned
}
@@ -695,7 +767,10 @@ abstract class Data extends HasId with NamedComponent with SourceInfoDoc {
* @note Aggregates are recursively packed with the first element appearing
* in the least-significant bits of the result.
*/
- final def asUInt(): UInt = macro SourceInfoTransform.noArg
+ final def asUInt: UInt = macro SourceInfoTransform.noArg
+
+ @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5")
+ final def asUInt(dummy: Int*): UInt = macro SourceInfoTransform.noArgDummy
/** @group SourceInfoTransformMacro */
def do_asUInt(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt
@@ -715,7 +790,7 @@ trait WireFactory {
val x = t.cloneTypeFull
// Bind each element of x to being a Wire
- x.bind(WireBinding(Builder.forcedUserModule, Builder.currentWhen()))
+ x.bind(WireBinding(Builder.forcedUserModule, Builder.currentWhen))
pushCommand(DefWire(sourceInfo, x))
if (!compileOptions.explicitInvalidate) {
diff --git a/core/src/main/scala/chisel3/Mem.scala b/core/src/main/scala/chisel3/Mem.scala
index 183620b6..aeacf052 100644
--- a/core/src/main/scala/chisel3/Mem.scala
+++ b/core/src/main/scala/chisel3/Mem.scala
@@ -130,7 +130,7 @@ sealed abstract class MemBase[T <: Data](val t: T, val length: BigInt) extends H
t.cloneTypeFull, Node(this), dir, i.ref, Builder.forcedClock.ref)
).id
// Bind each element of port to being a MemoryPort
- port.bind(MemoryPortBinding(Builder.forcedUserModule, Builder.currentWhen()))
+ port.bind(MemoryPortBinding(Builder.forcedUserModule, Builder.currentWhen))
port
}
}
diff --git a/core/src/main/scala/chisel3/Module.scala b/core/src/main/scala/chisel3/Module.scala
index 3ae48821..7ba24585 100644
--- a/core/src/main/scala/chisel3/Module.scala
+++ b/core/src/main/scala/chisel3/Module.scala
@@ -39,7 +39,7 @@ object Module extends SourceInfoDoc {
// Save then clear clock and reset to prevent leaking scope, must be set again in the Module
val (saveClock, saveReset) = (Builder.currentClock, Builder.currentReset)
- val savePrefix = Builder.getPrefix()
+ val savePrefix = Builder.getPrefix
Builder.clearPrefix()
Builder.currentClock = None
Builder.currentReset = None
@@ -88,6 +88,16 @@ object Module extends SourceInfoDoc {
def reset: Reset = Builder.forcedReset
/** Returns the current Module */
def currentModule: Option[BaseModule] = Builder.currentModule
+
+ private[chisel3] def do_pseudo_apply[T <: BaseModule](bc: => T)
+ (implicit sourceInfo: SourceInfo,
+ compileOptions: CompileOptions): T = {
+ val parent = Builder.currentModule
+
+ val module: T = bc // bc is actually evaluated here
+
+ module
+ }
}
/** Abstract base class for Modules, which behave much like Verilog modules.
@@ -182,23 +192,33 @@ package experimental {
package internal {
import chisel3.experimental.BaseModule
- import chisel3.experimental.hierarchy.IsInstantiable
+ import chisel3.experimental.hierarchy.{IsInstantiable, Proto, Clone}
object BaseModule {
/** Represents a clone of an underlying object. This is used to support CloneModuleAsRecord and Instance/Definition.
*
* @note We don't actually "clone" anything in the traditional sense but is a placeholder so we lazily clone internal state
*/
- private [chisel3] trait IsClone[+T] {
+ trait IsClone[+T] {
// Underlying object of which this is a clone of
- val _proto: T
- def getProto: T = _proto
- def isACloneOf(a: Any): Boolean = this == a || _proto == a
+ private[chisel3] def getProto: T
+
+ /** Determines whether another object is a clone of the same underlying proto
+ *
+ * @param a
+ */
+ def hasSameProto(a: Any): Boolean = {
+ val aProto = a match {
+ case x: IsClone[BaseModule] => x.getProto
+ case o => o
+ }
+ this == aProto || getProto == aProto
+ }
}
// Private internal class to serve as a _parent for Data in cloned ports
- private[chisel3] class ModuleClone[T <: BaseModule] (val _proto: T) extends PseudoModule with IsClone[T] {
- override def toString = s"ModuleClone(${_proto})"
+ private[chisel3] class ModuleClone[T <: BaseModule] (val getProto: T) extends PseudoModule with IsClone[T] {
+ override def toString = s"ModuleClone(${getProto})"
def getPorts = _portsRecord
// ClonePorts that hold the bound ports for this module
// Used for setting the refs of both this module and the Record
@@ -211,19 +231,19 @@ package internal {
private[chisel3] def generateComponent(): Option[Component] = {
require(!_closed, "Can't generate module more than once")
_closed = true
- _component = _proto._component
+ _component = getProto._component
None
}
// Maps proto ports to module clone's ports
private[chisel3] lazy val ioMap: Map[Data, Data] = {
val name2Port = getPorts.elements
- _proto.getChiselPorts.map { case (name, data) => data -> name2Port(name) }.toMap
+ getProto.getChiselPorts.map { case (name, data) => data -> name2Port(name) }.toMap
}
// This module doesn't actually exist in the FIRRTL so no initialization to do
private[chisel3] def initializeInParent(parentCompileOptions: CompileOptions): Unit = ()
// Name of this instance's module is the same as the proto's name
- override def desiredName: String = _proto.name
+ override def desiredName: String = getProto.name
private[chisel3] def setRefAndPortsRef(namespace: Namespace): Unit = {
val record = _portsRecord
@@ -235,7 +255,7 @@ package internal {
case bad => throwException(s"Internal Error! Cloned-module Record $record has unexpected ref $bad")
}
// Set both the record and the module to have the same instance name
- record.setRef(ModuleCloneIO(_proto, instName), force=true) // force because we did .forceName first
+ record.setRef(ModuleCloneIO(getProto, instName), force=true) // force because we did .forceName first
this.setRef(Ref(instName))
}
}
@@ -249,8 +269,8 @@ package internal {
* @note In addition, the instance name of an InstanceClone is going to be the SAME as the proto, but this is not true
* for ModuleClone.
*/
- private[chisel3] final class InstanceClone[T <: BaseModule] (val _proto: T, val instName: () => String) extends PseudoModule with IsClone[T] {
- override def toString = s"InstanceClone(${_proto})"
+ private[chisel3] final class InstanceClone[T <: BaseModule] (val getProto: T, val instName: () => String) extends PseudoModule with IsClone[T] {
+ override def toString = s"InstanceClone(${getProto})"
// No addition components are generated
private[chisel3] def generateComponent(): Option[Component] = None
// Necessary for toTarget to work
@@ -260,7 +280,7 @@ package internal {
// Instance name is the same as proto's instance name
override def instanceName = instName()
// Module name is the same as proto's module name
- override def desiredName: String = _proto.name
+ override def desiredName: String = getProto.name
}
/** Represents a Definition root module, when accessing something from a definition
@@ -271,20 +291,21 @@ package internal {
* target whose root is the Definition. This DefinitionClone is used to represent the root parent of the
* InstanceClone (which represents the returned module).
*/
- private[chisel3] class DefinitionClone[T <: BaseModule] (val _proto: T) extends PseudoModule with IsClone[T] {
- override def toString = s"DefinitionClone(${_proto})"
+ private[chisel3] class DefinitionClone[T <: BaseModule] (val getProto: T) extends PseudoModule with IsClone[T] {
+ override def toString = s"DefinitionClone(${getProto})"
// No addition components are generated
private[chisel3] def generateComponent(): Option[Component] = None
// Necessary for toTarget to work
private[chisel3] def initializeInParent(parentCompileOptions: CompileOptions): Unit = ()
// Module name is the same as proto's module name
- override def desiredName: String = _proto.name
+ override def desiredName: String = getProto.name
}
/** @note If we are cloning a non-module, we need another object which has the proper _parent set!
*/
- private[chisel3] final class InstantiableClone[T <: IsInstantiable] (val _proto: T) extends IsClone[T] {
- private[chisel3] var _parent: Option[BaseModule] = internal.Builder.currentModule
+ trait InstantiableClone[T <: IsInstantiable] extends IsClone[T] {
+ private[chisel3] def _innerContext: experimental.hierarchy.Hierarchy[_]
+ private[chisel3] def getInnerContext: Option[BaseModule] = _innerContext.getInnerDataContext
}
/** Record type returned by CloneModuleAsRecord
@@ -328,13 +349,13 @@ package internal {
package experimental {
- import chisel3.experimental.hierarchy.IsInstantiable
+ import chisel3.experimental.hierarchy.{IsInstantiable, Proto}
object BaseModule {
implicit class BaseModuleExtensions[T <: BaseModule](b: T) {
import chisel3.experimental.hierarchy.{Instance, Definition}
- def toInstance: Instance[T] = new Instance(Left(b))
- def toDefinition: Definition[T] = new Definition(Left(b))
+ def toInstance: Instance[T] = new Instance(Proto(b))
+ def toDefinition: Definition[T] = new Definition(Proto(b))
}
}
/** Abstract base class for Modules, an instantiable organizational unit for RTL.
@@ -346,13 +367,19 @@ package experimental {
//
// Builder Internals - this tracks which Module RTL construction belongs to.
//
- if (!Builder.readyForModuleConstr) {
- throwException("Error: attempted to instantiate a Module without wrapping it in Module().")
+ this match {
+ case _: PseudoModule =>
+ case other =>
+ if (!Builder.readyForModuleConstr) {
+ throwException("Error: attempted to instantiate a Module without wrapping it in Module().")
+ }
}
- readyForModuleConstr = false
+ if (Builder.hasDynamicContext) {
+ readyForModuleConstr = false
- Builder.currentModule = Some(this)
- Builder.whenStack = Nil
+ Builder.currentModule = Some(this)
+ Builder.whenStack = Nil
+ }
//
// Module Construction Internals
diff --git a/core/src/main/scala/chisel3/Num.scala b/core/src/main/scala/chisel3/Num.scala
index 6dd299f4..219e18f4 100644
--- a/core/src/main/scala/chisel3/Num.scala
+++ b/core/src/main/scala/chisel3/Num.scala
@@ -148,7 +148,10 @@ trait Num[T <: Data] {
* $unchangedWidth
* @group Arithmetic
*/
- final def abs(): T = macro SourceInfoTransform.noArg
+ final def abs: T = macro SourceInfoTransform.noArg
+
+ @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5")
+ final def abs(dummy: Int*): T = macro SourceInfoTransform.noArgDummy
/** @group SourceInfoTransformMacro */
def do_abs(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T
diff --git a/core/src/main/scala/chisel3/Printf.scala b/core/src/main/scala/chisel3/Printf.scala
index cf7821b8..be0146bb 100644
--- a/core/src/main/scala/chisel3/Printf.scala
+++ b/core/src/main/scala/chisel3/Printf.scala
@@ -6,7 +6,6 @@ import scala.language.experimental.macros
import chisel3.internal._
import chisel3.internal.Builder.pushCommand
import chisel3.internal.sourceinfo.SourceInfo
-import chisel3.experimental.BaseSim
/** Prints a message in simulation
*
@@ -34,7 +33,7 @@ object printf {
}
/** Named class for [[printf]]s. */
- final class Printf(val pable: Printable) extends BaseSim
+ final class Printf private[chisel3](val pable: Printable) extends VerificationStatement
/** Prints a message in simulation
*
diff --git a/core/src/main/scala/chisel3/RawModule.scala b/core/src/main/scala/chisel3/RawModule.scala
index 27f16ad4..e977d918 100644
--- a/core/src/main/scala/chisel3/RawModule.scala
+++ b/core/src/main/scala/chisel3/RawModule.scala
@@ -5,7 +5,8 @@ package chisel3
import scala.collection.mutable.{ArrayBuffer, HashMap}
import scala.util.Try
import scala.language.experimental.macros
-import chisel3.experimental.{BaseModule, BaseSim}
+import scala.annotation.nowarn
+import chisel3.experimental.BaseModule
import chisel3.internal._
import chisel3.internal.BaseModule.{ModuleClone, InstanceClone}
import chisel3.internal.Builder._
@@ -17,6 +18,7 @@ import _root_.firrtl.annotations.{IsModule, ModuleTarget}
* This abstract base class is a user-defined module which does not include implicit clock and reset and supports
* multiple IO() declarations.
*/
+@nowarn("msg=class Port") // delete when Port becomes private
abstract class RawModule(implicit moduleCompileOptions: CompileOptions)
extends BaseModule {
//
@@ -35,16 +37,16 @@ abstract class RawModule(implicit moduleCompileOptions: CompileOptions)
//
// Other Internal Functions
//
- // For debuggers/testers, TODO: refactor out into proper public API
private var _firrtlPorts: Option[Seq[firrtl.Port]] = None
- @deprecated("Use DataMirror.fullModulePorts instead. this API will be removed in Chisel 3.6", "Chisel 3.5")
- lazy val getPorts = _firrtlPorts.get
+
+ @deprecated("Use DataMirror.modulePorts instead. this API will be removed in Chisel 3.6", "Chisel 3.5")
+ lazy val getPorts: Seq[Port] = _firrtlPorts.get
val compileOptions = moduleCompileOptions
private[chisel3] def namePorts(names: HashMap[HasId, String]): Unit = {
for (port <- getModulePorts) {
- port.computeName(None, None).orElse(names.get(port)) match {
+ port._computeName(None, None).orElse(names.get(port)) match {
case Some(name) =>
if (_namespace.contains(name)) {
Builder.error(s"""Unable to name port $port to "$name" in $this,""" +
@@ -81,7 +83,11 @@ abstract class RawModule(implicit moduleCompileOptions: CompileOptions)
case id: InstanceClone[_] => id.setAsInstanceRef()
case id: BaseModule => id.forceName(None, default=id.desiredName, _namespace)
case id: MemBase[_] => id.forceName(None, default="MEM", _namespace)
- case id: BaseSim => id.forceName(None, default="SIM", _namespace)
+ case id: stop.Stop => id.forceName(None, default="stop", _namespace)
+ case id: assert.Assert => id.forceName(None, default="assert", _namespace)
+ case id: assume.Assume => id.forceName(None, default="assume", _namespace)
+ case id: cover.Cover => id.forceName(None, default="cover", _namespace)
+ case id: printf.Printf => id.forceName(None, default="printf", _namespace)
case id: Data =>
if (id.isSynthesizable) {
id.topBinding match {
@@ -195,7 +201,7 @@ package object internal {
tryJavaReflect
.orElse(tryScalaReflect)
- .map(_.autoSeed("io"))
+ .map(_.forceFinalName("io"))
.orElse {
// Fallback if reflection fails, user can wrap in IO(...)
self.findPort("io")
diff --git a/core/src/main/scala/chisel3/Reg.scala b/core/src/main/scala/chisel3/Reg.scala
index bd9e5311..122c5ebd 100644
--- a/core/src/main/scala/chisel3/Reg.scala
+++ b/core/src/main/scala/chisel3/Reg.scala
@@ -41,7 +41,7 @@ object Reg {
val reg = t.cloneTypeFull
val clock = Node(Builder.forcedClock)
- reg.bind(RegBinding(Builder.forcedUserModule, Builder.currentWhen()))
+ reg.bind(RegBinding(Builder.forcedUserModule, Builder.currentWhen))
pushCommand(DefReg(sourceInfo, reg, clock))
reg
}
@@ -174,7 +174,7 @@ object RegInit {
val clock = Builder.forcedClock
val reset = Builder.forcedReset
- reg.bind(RegBinding(Builder.forcedUserModule, Builder.currentWhen()))
+ reg.bind(RegBinding(Builder.forcedUserModule, Builder.currentWhen))
requireIsHardware(init, "reg initializer")
pushCommand(DefRegInit(sourceInfo, reg, clock.ref, reset.ref, init.ref))
reg
diff --git a/core/src/main/scala/chisel3/SeqUtils.scala b/core/src/main/scala/chisel3/SeqUtils.scala
index da6fc802..5c86efd3 100644
--- a/core/src/main/scala/chisel3/SeqUtils.scala
+++ b/core/src/main/scala/chisel3/SeqUtils.scala
@@ -81,7 +81,7 @@ private[chisel3] object SeqUtils {
val output = cloneSupertype(in.toSeq map { _._2}, "oneHotMux")
def buildAndOrMultiplexor[TT <: Data](inputs: Iterable[(Bool, TT)]): T = {
- val masked = for ((s, i) <- inputs) yield Mux(s, i.asUInt(), 0.U)
+ val masked = for ((s, i) <- inputs) yield Mux(s, i.asUInt, 0.U)
masked.reduceLeft(_ | _).asTypeOf(output)
}
diff --git a/core/src/main/scala/chisel3/StrongEnum.scala b/core/src/main/scala/chisel3/StrongEnum.scala
index b3d7cf7d..fa420e80 100644
--- a/core/src/main/scala/chisel3/StrongEnum.scala
+++ b/core/src/main/scala/chisel3/StrongEnum.scala
@@ -72,17 +72,18 @@ import EnumAnnotations._
abstract class EnumType(private val factory: EnumFactory, selfAnnotating: Boolean = true) extends Element {
+
+ // Use getSimpleName instead of enumTypeName because for debugging purposes
+ // the fully qualified name isn't necessary (compared to for the
+ // Enum annotation), and it's more consistent with Bundle printing.
override def toString: String = {
- val bindingString = litOption match {
+ litOption match {
case Some(value) => factory.nameOfValue(value) match {
- case Some(name) => s"($value=$name)"
- case None => s"($value=(invalid))"
+ case Some(name) => s"${factory.getClass.getSimpleName.init}($value=$name)"
+ case None => stringAccessor(s"${factory.getClass.getSimpleName.init}($value=(invalid))")
}
- case _ => bindingToString
+ case _ => stringAccessor(s"${factory.getClass.getSimpleName.init}")
}
- // Use getSimpleName instead of enumTypeName because for debugging purposes the fully qualified name isn't
- // necessary (compared to for the Enum annotation), and it's more consistent with Bundle printing.
- s"${factory.getClass.getSimpleName.init}$bindingString"
}
override def cloneType: this.type = factory().asInstanceOf[this.type]
@@ -246,7 +247,7 @@ abstract class EnumFactory {
private val enumRecords = mutable.ArrayBuffer.empty[EnumRecord]
private def enumNames = enumRecords.map(_.name).toSeq
- private def enumValues = enumRecords.map(_.inst.litValue()).toSeq
+ private def enumValues = enumRecords.map(_.inst.litValue).toSeq
private def enumInstances = enumRecords.map(_.inst).toSeq
private[chisel3] val enumTypeName = getClass.getName.init
@@ -265,7 +266,7 @@ abstract class EnumFactory {
def all: Seq[Type] = enumInstances
private[chisel3] def nameOfValue(id: BigInt): Option[String] = {
- enumRecords.find(_.inst.litValue() == id).map(_.name)
+ enumRecords.find(_.inst.litValue == id).map(_.name)
}
protected def Value: Type = macro EnumMacros.ValImpl
@@ -291,11 +292,11 @@ abstract class EnumFactory {
if (id.litOption.isEmpty) {
throwException(s"$enumTypeName defined with a non-literal type")
}
- if (id.litValue() < this.id) {
+ if (id.litValue < this.id) {
throwException(s"Enums must be strictly increasing: $enumTypeName")
}
- this.id = id.litValue()
+ this.id = id.litValue
do_Value(name)
}
diff --git a/core/src/main/scala/chisel3/VerificationStatement.scala b/core/src/main/scala/chisel3/VerificationStatement.scala
new file mode 100644
index 00000000..23adc192
--- /dev/null
+++ b/core/src/main/scala/chisel3/VerificationStatement.scala
@@ -0,0 +1,236 @@
+// SPDX-License-Identifier: Apache-2.0
+
+package chisel3
+
+import scala.reflect.macros.blackbox.Context
+import scala.language.experimental.macros
+import chisel3.internal._
+import chisel3.internal.Builder.pushCommand
+import chisel3.internal.firrtl._
+import chisel3.internal.sourceinfo.SourceInfo
+
+import scala.reflect.macros.blackbox
+
+object assert {
+ /** Checks for a condition to be valid in the circuit at all times. If the
+ * condition evaluates to false, the circuit simulation stops with an error.
+ *
+ * Does not fire when in reset (defined as the encapsulating Module's
+ * reset). If your definition of reset is not the encapsulating Module's
+ * reset, you will need to gate this externally.
+ *
+ * May be called outside of a Module (like defined in a function), so
+ * functions using assert make the standard Module assumptions (single clock
+ * and single reset).
+ *
+ * @param cond condition, assertion fires (simulation fails) when false
+ * @param message optional format string to print when the assertion fires
+ * @param data optional bits to print in the message formatting
+ *
+ * @note See [[printf.apply(fmt:String* printf]] for format string documentation
+ * @note currently cannot be used in core Chisel / libraries because macro
+ * defs need to be compiled first and the SBT project is not set up to do
+ * that
+ */
+ // Macros currently can't take default arguments, so we need two functions to emulate defaults.
+ def apply(cond: Bool, message: String, data: Bits*)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Assert = macro _applyMacroWithMessage
+ def apply(cond: Bool)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Assert = macro _applyMacroWithNoMessage
+
+ /** An elaboration-time assertion. Calls the built-in Scala assert function. */
+ def apply(cond: Boolean, message: => String): Unit = Predef.assert(cond, message)
+ /** An elaboration-time assertion. Calls the built-in Scala assert function. */
+ def apply(cond: Boolean): Unit = Predef.assert(cond, "")
+
+ /** Named class for assertions. */
+ final class Assert private[chisel3]() extends VerificationStatement
+
+ import VerificationStatement._
+
+ def _applyMacroWithMessage(c: blackbox.Context)(cond: c.Tree, message: c.Tree, data: c.Tree*)(sourceInfo: c.Tree, compileOptions: c.Tree): c.Tree = {
+ import c.universe._
+ val apply_impl_do = symbolOf[this.type].asClass.module.info.member(TermName("_applyWithSourceLine"))
+ q"$apply_impl_do($cond, ${getLine(c)}, _root_.scala.Some($message), ..$data)($sourceInfo, $compileOptions)"
+ }
+
+ def _applyMacroWithNoMessage(c: blackbox.Context)(cond: c.Tree)(sourceInfo: c.Tree, compileOptions: c.Tree): c.Tree = {
+ import c.universe._
+ val apply_impl_do = symbolOf[this.type].asClass.module.info.member(TermName("_applyWithSourceLine"))
+ q"$apply_impl_do($cond, ${getLine(c)}, _root_.scala.None)($sourceInfo, $compileOptions)"
+ }
+
+ /** Used by our macros. Do not call directly! */
+ def _applyWithSourceLine(cond: Bool, line: SourceLineInfo, message: Option[String], data: Bits*)
+ (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Assert = {
+ val id = new Assert()
+ when(!Module.reset.asBool()) {
+ Builder.pushCommand(Verification(id, Formal.Assert, sourceInfo, Module.clock.ref, cond.ref, ""))
+ failureMessage("Assertion", line, cond, message, data)
+ }
+ id
+ }
+}
+
+
+object assume {
+ /** Assumes a condition to be valid in the circuit at all times.
+ * Acts like an assertion in simulation and imposes a declarative
+ * assumption on the state explored by formal tools.
+ *
+ * Does not fire when in reset (defined as the encapsulating Module's
+ * reset). If your definition of reset is not the encapsulating Module's
+ * reset, you will need to gate this externally.
+ *
+ * May be called outside of a Module (like defined in a function), so
+ * functions using assert make the standard Module assumptions (single clock
+ * and single reset).
+ *
+ * @param cond condition, assertion fires (simulation fails) when false
+ * @param message optional format string to print when the assertion fires
+ * @param data optional bits to print in the message formatting
+ *
+ * @note See [[printf.apply(fmt:String* printf]] for format string documentation
+ */
+ // Macros currently can't take default arguments, so we need two functions to emulate defaults.
+ def apply(cond: Bool, message: String, data: Bits*)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Assume = macro _applyMacroWithMessage
+ def apply(cond: Bool)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Assume = macro _applyMacroWithNoMessage
+
+ /** An elaboration-time assumption. Calls the built-in Scala assume function. */
+ def apply(cond: Boolean, message: => String): Unit = Predef.assume(cond, message)
+ /** An elaboration-time assumption. Calls the built-in Scala assume function. */
+ def apply(cond: Boolean): Unit = Predef.assume(cond, "")
+
+ /** Named class for assumptions. */
+ final class Assume private[chisel3]() extends VerificationStatement
+
+ import VerificationStatement._
+
+ def _applyMacroWithMessage(c: blackbox.Context)(cond: c.Tree, message: c.Tree, data: c.Tree*)(sourceInfo: c.Tree, compileOptions: c.Tree): c.Tree = {
+ import c.universe._
+ val apply_impl_do = symbolOf[this.type].asClass.module.info.member(TermName("_applyWithSourceLine"))
+ q"$apply_impl_do($cond, ${getLine(c)}, _root_.scala.Some($message), ..$data)($sourceInfo, $compileOptions)"
+ }
+
+ def _applyMacroWithNoMessage(c: blackbox.Context)(cond: c.Tree)(sourceInfo: c.Tree, compileOptions: c.Tree): c.Tree = {
+ import c.universe._
+ val apply_impl_do = symbolOf[this.type].asClass.module.info.member(TermName("_applyWithSourceLine"))
+ q"$apply_impl_do($cond, ${getLine(c)}, _root_.scala.None)($sourceInfo, $compileOptions)"
+ }
+
+ /** Used by our macros. Do not call directly! */
+ def _applyWithSourceLine(cond: Bool, line: SourceLineInfo, message: Option[String], data: Bits*)
+ (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Assume = {
+ val id = new Assume()
+ when(!Module.reset.asBool()) {
+ Builder.pushCommand(Verification(id, Formal.Assume, sourceInfo, Module.clock.ref, cond.ref, ""))
+ failureMessage("Assumption", line, cond, message, data)
+ }
+ id
+ }
+}
+
+
+object cover {
+ /** Declares a condition to be covered.
+ * At ever clock event, a counter is incremented iff the condition is active
+ * and reset is inactive.
+ *
+ * Does not fire when in reset (defined as the encapsulating Module's
+ * reset). If your definition of reset is not the encapsulating Module's
+ * reset, you will need to gate this externally.
+ *
+ * May be called outside of a Module (like defined in a function), so
+ * functions using assert make the standard Module assumptions (single clock
+ * and single reset).
+ *
+ * @param cond condition that will be sampled on every clock tick
+ * @param message a string describing the cover event
+ */
+ // Macros currently can't take default arguments, so we need two functions to emulate defaults.
+ def apply(cond: Bool, message: String)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Cover = macro _applyMacroWithMessage
+ def apply(cond: Bool)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Cover = macro _applyMacroWithNoMessage
+
+ /** Named class for cover statements. */
+ final class Cover private[chisel3]() extends VerificationStatement
+
+ import VerificationStatement._
+
+ def _applyMacroWithNoMessage(c: blackbox.Context)(cond: c.Tree)(sourceInfo: c.Tree, compileOptions: c.Tree): c.Tree = {
+ import c.universe._
+ val apply_impl_do = symbolOf[this.type].asClass.module.info.member(TermName("_applyWithSourceLine"))
+ q"$apply_impl_do($cond, ${getLine(c)}, _root_.scala.None)($sourceInfo, $compileOptions)"
+ }
+
+ def _applyMacroWithMessage(c: blackbox.Context)(cond: c.Tree, message: c.Tree)(sourceInfo: c.Tree, compileOptions: c.Tree): c.Tree = {
+ import c.universe._
+ val apply_impl_do = symbolOf[this.type].asClass.module.info.member(TermName("_applyWithSourceLine"))
+ q"$apply_impl_do($cond, ${getLine(c)}, _root_.scala.Some($message))($sourceInfo, $compileOptions)"
+ }
+
+ /** Used by our macros. Do not call directly! */
+ def _applyWithSourceLine(cond: Bool, line: SourceLineInfo, message: Option[String])
+ (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Cover = {
+ val id = new Cover()
+ when(!Module.reset.asBool()) {
+ Builder.pushCommand(Verification(id, Formal.Cover, sourceInfo, Module.clock.ref, cond.ref, ""))
+ }
+ id
+ }
+}
+
+object stop {
+ /** Terminate execution, indicating success.
+ *
+ * @param message a string describing why the simulation was stopped
+ */
+ def apply(message: String = "")(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Stop = {
+ val stp = new Stop()
+ when (!Module.reset.asBool) {
+ pushCommand(Stop(stp, sourceInfo, Builder.forcedClock.ref, 0))
+ }
+ stp
+ }
+
+ /** Terminate execution with a failure code. */
+ @deprecated("Non-zero return codes are not well supported. Please use assert(false.B) if you want to indicate a failure.", "Chisel 3.5")
+ def apply(code: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Stop = {
+ val stp = new Stop()
+ when (!Module.reset.asBool) {
+ pushCommand(Stop(stp, sourceInfo, Builder.forcedClock.ref, code))
+ }
+ stp
+ }
+
+ /** Named class for [[stop]]s. */
+ final class Stop private[chisel3]()extends VerificationStatement
+}
+
+/** Base class for all verification statements: Assert, Assume, Cover, Stop and Printf. */
+abstract class VerificationStatement extends NamedComponent {
+ _parent.foreach(_.addId(this))
+}
+
+/** Helper functions for common functionality required by stop, assert, assume or cover */
+private object VerificationStatement {
+
+ type SourceLineInfo = (String, Int, String)
+
+ def getLine(c: blackbox.Context): SourceLineInfo = {
+ val p = c.enclosingPosition
+ (p.source.file.name, p.line, p.lineContent.trim)
+ }
+
+ // creates a printf to inform the user of a failed assertion or assumption
+ def failureMessage(kind: String, lineInfo: SourceLineInfo, cond: Bool, message: Option[String], data: Seq[Bits])
+ (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions) : Unit = {
+ val (filename, line, content) = lineInfo
+ val lineMsg = s"$filename:$line $content".replaceAll("%", "%%")
+ val fmt = message match {
+ case Some(msg) =>
+ s"$kind failed: $msg\n at $lineMsg\n"
+ case None => s"$kind failed\n at $lineMsg\n"
+ }
+ when(!cond) {
+ printf.printfWithoutReset(fmt, data:_*)
+ }
+ }
+}
diff --git a/core/src/main/scala/chisel3/When.scala b/core/src/main/scala/chisel3/When.scala
index a2c20d9a..ca383c0f 100644
--- a/core/src/main/scala/chisel3/When.scala
+++ b/core/src/main/scala/chisel3/When.scala
@@ -50,7 +50,7 @@ object when {
implicit val sourceInfo = UnlocatableSourceInfo
val whens = Builder.whenStack
whens.foldRight(true.B) {
- case (ctx, acc) => acc && ctx.localCond()
+ case (ctx, acc) => acc && ctx.localCond
}
}
}
@@ -81,7 +81,7 @@ final class WhenContext private[chisel3] (
private var scopeOpen = false
/** Returns the local condition, inverted for an otherwise */
- private[chisel3] def localCond(): Bool = {
+ private[chisel3] def localCond: Bool = {
implicit val compileOptions = ExplicitCompileOptions.Strict
implicit val sourceInfo = UnlocatableSourceInfo
val alt = altConds.foldRight(true.B) {
@@ -111,7 +111,10 @@ final class WhenContext private[chisel3] (
def otherwise(block: => Any)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Unit =
new WhenContext(sourceInfo, None, block, firrtlDepth + 1, cond ++: altConds)
- def active(): Boolean = scopeOpen
+ def active: Boolean = scopeOpen
+
+ @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5")
+ def active(dummy: Int*): Boolean = active
/*
*
diff --git a/core/src/main/scala/chisel3/experimental/Analog.scala b/core/src/main/scala/chisel3/experimental/Analog.scala
index 6cca81f5..e94bae2d 100644
--- a/core/src/main/scala/chisel3/experimental/Analog.scala
+++ b/core/src/main/scala/chisel3/experimental/Analog.scala
@@ -27,9 +27,7 @@ import scala.collection.mutable
final class Analog private (private[chisel3] val width: Width) extends Element {
require(width.known, "Since Analog is only for use in BlackBoxes, width must be known")
- override def toString: String = {
- s"Analog$width$bindingToString"
- }
+ override def toString: String = stringAccessor(s"Analog$width")
private[chisel3] override def typeEquivalent(that: Data): Boolean =
that.isInstanceOf[Analog] && this.width == that.width
diff --git a/core/src/main/scala/chisel3/experimental/Trace.scala b/core/src/main/scala/chisel3/experimental/Trace.scala
new file mode 100644
index 00000000..2d965c7b
--- /dev/null
+++ b/core/src/main/scala/chisel3/experimental/Trace.scala
@@ -0,0 +1,69 @@
+package chisel3.experimental
+
+import chisel3.internal.HasId
+import chisel3.{Aggregate, Data, Element, Module}
+import firrtl.AnnotationSeq
+import firrtl.annotations.{Annotation, CompleteTarget, SingleTargetAnnotation}
+import firrtl.transforms.DontTouchAllTargets
+
+/** The util that records the reference map from original [[Data]]/[[Module]] annotated in Chisel and final FIRRTL.
+ * @example
+ * {{{
+ * class Dut extends Module {
+ * val a = WireDefault(Bool())
+ * Trace.traceName(a)
+ * }
+ * val annos = (new ChiselStage).execute(Seq(ChiselGeneratorAnnotation(() => new Dut)))
+ * val dut = annos.collectFirst { case DesignAnnotation(dut) => dut }.get.asInstanceOf[CollideModule]
+ * // get final reference of `a` Seq(ReferenceTarget("Dut", "Dut", Seq.empty, "a", Seq.empty))
+ * val firrtlReferenceOfDutA = finalTarget(annos)(dut.a)
+ * }}}
+ * */
+object Trace {
+
+ /** Trace a Instance name. */
+ def traceName(x: Module): Unit = {
+ annotate(new ChiselAnnotation {
+ def toFirrtl: Annotation = TraceNameAnnotation(x.toAbsoluteTarget, x.toAbsoluteTarget)
+ })
+ }
+
+ /** Trace a Data name. */
+ def traceName(x: Data): Unit = {
+ x match {
+ case aggregate: Aggregate =>
+ annotate(new ChiselAnnotation {
+ def toFirrtl: Annotation = TraceNameAnnotation(aggregate.toAbsoluteTarget, aggregate.toAbsoluteTarget)
+ })
+ aggregate.getElements.foreach(traceName)
+ case element: Element =>
+ annotate(new ChiselAnnotation {
+ def toFirrtl: Annotation = TraceNameAnnotation(element.toAbsoluteTarget, element.toAbsoluteTarget)
+ })
+ }
+ }
+
+ /** An Annotation that records the original target annotate from Chisel.
+ *
+ * @param target target that should be renamed by [[firrtl.RenameMap]] in the firrtl transforms.
+ * @param chiselTarget original annotated target in Chisel, which should not be changed or renamed in FIRRTL.
+ */
+ private case class TraceNameAnnotation[T <: CompleteTarget](target: T, chiselTarget: T)
+ extends SingleTargetAnnotation[T]
+ with DontTouchAllTargets {
+ def duplicate(n: T): Annotation = this.copy(target = n)
+ }
+
+ /** Get [[CompleteTarget]] of the target `x` for `annos`.
+ * This API can be used to find the final reference to a signal or module which is marked by `traceName`
+ */
+ def finalTarget(annos: AnnotationSeq)(x: HasId): Seq[CompleteTarget] = finalTargetMap(annos)
+ .getOrElse(x.toAbsoluteTarget, Seq.empty)
+
+ /** Get all traced signal/module for `annos`
+ * This API can be used to gather all final reference to the signal or module which is marked by `traceName`
+ */
+ def finalTargetMap(annos: AnnotationSeq): Map[CompleteTarget, Seq[CompleteTarget]] = annos.collect {
+ case TraceNameAnnotation(t, chiselTarget) => chiselTarget -> t
+ }.groupBy(_._1).map{case (k, v) => k -> v.map(_._2)}
+}
diff --git a/core/src/main/scala/chisel3/experimental/dataview/DataProduct.scala b/core/src/main/scala/chisel3/experimental/dataview/DataProduct.scala
index 55dd8505..438f97b8 100644
--- a/core/src/main/scala/chisel3/experimental/dataview/DataProduct.scala
+++ b/core/src/main/scala/chisel3/experimental/dataview/DataProduct.scala
@@ -3,7 +3,7 @@
package chisel3.experimental.dataview
import chisel3.experimental.BaseModule
-import chisel3.{Data, getRecursiveFields}
+import chisel3.{Data, Vec, getRecursiveFields}
import scala.annotation.implicitNotFound
@@ -41,17 +41,24 @@ trait DataProduct[-A] {
def dataSet(a: A): Data => Boolean = dataIterator(a, "").map(_._1).toSet
}
-/** Encapsulating object for automatically provided implementations of [[DataProduct]]
+/** Low priority built-in implementations of [[DataProduct]]
*
- * @note DataProduct implementations provided in this object are available in the implicit scope
+ * @note This trait exists so that `dataDataProduct` can be lower priority than `seqDataProduct` to resolve ambiguity
*/
-object DataProduct {
+sealed trait LowPriorityDataProduct {
+
/** [[DataProduct]] implementation for [[Data]] */
implicit val dataDataProduct: DataProduct[Data] = new DataProduct[Data] {
def dataIterator(a: Data, path: String): Iterator[(Data, String)] =
getRecursiveFields.lazily(a, path).iterator
}
+}
+/** Encapsulating object for built-in implementations of [[DataProduct]]
+ *
+ * @note DataProduct implementations provided in this object are available in the implicit scope
+ */
+object DataProduct extends LowPriorityDataProduct {
/** [[DataProduct]] implementation for [[BaseModule]] */
implicit val userModuleDataProduct: DataProduct[BaseModule] = new DataProduct[BaseModule] {
def dataIterator(a: BaseModule, path: String): Iterator[(Data, String)] = {
@@ -69,4 +76,237 @@ object DataProduct {
e => e._id > a._id && e._id <= lastId
}
}
+
+ /** [[DataProduct]] implementation for any `Seq[A]` where `A` has an implementation of `DataProduct`. */
+ implicit def seqDataProduct[A : DataProduct]: DataProduct[Seq[A]] = new DataProduct[Seq[A]] {
+ def dataIterator(a: Seq[A], path: String): Iterator[(Data, String)] = {
+ val dpa = implicitly[DataProduct[A]]
+ a.iterator
+ .zipWithIndex
+ .flatMap { case (elt, idx) =>
+ dpa.dataIterator(elt, s"$path[$idx]")
+ }
+ }
+ }
+
+ /** [[DataProduct]] implementation for any [[Tuple2]] where each field has an implementation of `DataProduct`. */
+ implicit def tuple2DataProduct[A : DataProduct, B : DataProduct]: DataProduct[(A, B)] = new DataProduct[(A, B)] {
+ def dataIterator(tup: (A, B), path: String): Iterator[(Data, String)] = {
+ val dpa = implicitly[DataProduct[A]]
+ val dpb = implicitly[DataProduct[B]]
+ val (a, b) = tup
+ dpa.dataIterator(a, s"$path._1") ++ dpb.dataIterator(b, s"$path._2")
+ }
+ }
+
+ /** [[DataProduct]] implementation for any [[Tuple3]] where each field has an implementation of `DataProduct`. */
+ implicit def tuple3DataProduct[A : DataProduct, B : DataProduct, C : DataProduct]: DataProduct[(A, B, C)] =
+ new DataProduct[(A, B, C)] {
+ def dataIterator(tup: (A, B, C), path: String): Iterator[(Data, String)] = {
+ val dpa = implicitly[DataProduct[A]]
+ val dpb = implicitly[DataProduct[B]]
+ val dpc = implicitly[DataProduct[C]]
+ val (a, b, c) = tup
+ dpa.dataIterator(a, s"$path._1") ++ dpb.dataIterator(b, s"$path._2") ++ dpc.dataIterator(c, s"$path._3")
+ }
+ }
+
+ /** [[DataProduct]] implementation for any [[Tuple4]] where each field has an implementation of `DataProduct`. */
+ implicit def tuple4DataProduct[A : DataProduct, B : DataProduct, C : DataProduct, D : DataProduct]: DataProduct[(A, B, C, D)] =
+ new DataProduct[(A, B, C, D)] {
+ def dataIterator(tup: (A, B, C, D), path: String): Iterator[(Data, String)] = {
+ val dpa = implicitly[DataProduct[A]]
+ val dpb = implicitly[DataProduct[B]]
+ val dpc = implicitly[DataProduct[C]]
+ val dpd = implicitly[DataProduct[D]]
+ val (a, b, c, d) = tup
+ dpa.dataIterator(a, s"$path._1") ++
+ dpb.dataIterator(b, s"$path._2") ++
+ dpc.dataIterator(c, s"$path._3") ++
+ dpd.dataIterator(d, s"$path._4")
+ }
+ }
+
+ /** [[DataProduct]] implementation for any [[Tuple5]] where each field has an implementation of `DataProduct`. */
+ implicit def tuple5DataProduct[
+ A : DataProduct,
+ B : DataProduct,
+ C : DataProduct,
+ D : DataProduct,
+ E : DataProduct]: DataProduct[(A, B, C, D, E)] =
+ new DataProduct[(A, B, C, D, E)] {
+ def dataIterator(tup: (A, B, C, D, E), path: String): Iterator[(Data, String)] = {
+ val dpa = implicitly[DataProduct[A]]
+ val dpb = implicitly[DataProduct[B]]
+ val dpc = implicitly[DataProduct[C]]
+ val dpd = implicitly[DataProduct[D]]
+ val dpe = implicitly[DataProduct[E]]
+ val (a, b, c, d, e) = tup
+ dpa.dataIterator(a, s"$path._1") ++
+ dpb.dataIterator(b, s"$path._2") ++
+ dpc.dataIterator(c, s"$path._3") ++
+ dpd.dataIterator(d, s"$path._4") ++
+ dpe.dataIterator(e, s"$path._5")
+ }
+ }
+
+ /** [[DataProduct]] implementation for any [[Tuple6]] where each field has an implementation of `DataProduct`. */
+ implicit def tuple6DataProduct[
+ A : DataProduct,
+ B : DataProduct,
+ C : DataProduct,
+ D : DataProduct,
+ E : DataProduct,
+ F : DataProduct]: DataProduct[(A, B, C, D, E, F)] =
+ new DataProduct[(A, B, C, D, E, F)] {
+ def dataIterator(tup: (A, B, C, D, E, F), path: String): Iterator[(Data, String)] = {
+ val dpa = implicitly[DataProduct[A]]
+ val dpb = implicitly[DataProduct[B]]
+ val dpc = implicitly[DataProduct[C]]
+ val dpd = implicitly[DataProduct[D]]
+ val dpe = implicitly[DataProduct[E]]
+ val dpf = implicitly[DataProduct[F]]
+ val (a, b, c, d, e, f) = tup
+ dpa.dataIterator(a, s"$path._1") ++
+ dpb.dataIterator(b, s"$path._2") ++
+ dpc.dataIterator(c, s"$path._3") ++
+ dpd.dataIterator(d, s"$path._4") ++
+ dpe.dataIterator(e, s"$path._5") ++
+ dpf.dataIterator(f, s"$path._6")
+ }
+ }
+
+ /** [[DataProduct]] implementation for any [[Tuple7]] where each field has an implementation of `DataProduct`. */
+ implicit def tuple7DataProduct[
+ A : DataProduct,
+ B : DataProduct,
+ C : DataProduct,
+ D : DataProduct,
+ E : DataProduct,
+ F : DataProduct,
+ G : DataProduct]: DataProduct[(A, B, C, D, E, F, G)] =
+ new DataProduct[(A, B, C, D, E, F, G)] {
+ def dataIterator(tup: (A, B, C, D, E, F, G), path: String): Iterator[(Data, String)] = {
+ val dpa = implicitly[DataProduct[A]]
+ val dpb = implicitly[DataProduct[B]]
+ val dpc = implicitly[DataProduct[C]]
+ val dpd = implicitly[DataProduct[D]]
+ val dpe = implicitly[DataProduct[E]]
+ val dpf = implicitly[DataProduct[F]]
+ val dpg = implicitly[DataProduct[G]]
+ val (a, b, c, d, e, f, g) = tup
+ dpa.dataIterator(a, s"$path._1") ++
+ dpb.dataIterator(b, s"$path._2") ++
+ dpc.dataIterator(c, s"$path._3") ++
+ dpd.dataIterator(d, s"$path._4") ++
+ dpe.dataIterator(e, s"$path._5") ++
+ dpf.dataIterator(f, s"$path._6") ++
+ dpg.dataIterator(g, s"$path._7")
+ }
+ }
+
+ /** [[DataProduct]] implementation for any [[Tuple8]] where each field has an implementation of `DataProduct`. */
+ implicit def tuple8DataProduct[
+ A : DataProduct,
+ B : DataProduct,
+ C : DataProduct,
+ D : DataProduct,
+ E : DataProduct,
+ F : DataProduct,
+ G : DataProduct,
+ H : DataProduct]: DataProduct[(A, B, C, D, E, F, G, H)] =
+ new DataProduct[(A, B, C, D, E, F, G, H)] {
+ def dataIterator(tup: (A, B, C, D, E, F, G, H), path: String): Iterator[(Data, String)] = {
+ val dpa = implicitly[DataProduct[A]]
+ val dpb = implicitly[DataProduct[B]]
+ val dpc = implicitly[DataProduct[C]]
+ val dpd = implicitly[DataProduct[D]]
+ val dpe = implicitly[DataProduct[E]]
+ val dpf = implicitly[DataProduct[F]]
+ val dpg = implicitly[DataProduct[G]]
+ val dph = implicitly[DataProduct[H]]
+ val (a, b, c, d, e, f, g, h) = tup
+ dpa.dataIterator(a, s"$path._1") ++
+ dpb.dataIterator(b, s"$path._2") ++
+ dpc.dataIterator(c, s"$path._3") ++
+ dpd.dataIterator(d, s"$path._4") ++
+ dpe.dataIterator(e, s"$path._5") ++
+ dpf.dataIterator(f, s"$path._6") ++
+ dpg.dataIterator(g, s"$path._7") ++
+ dph.dataIterator(h, s"$path._8")
+ }
+ }
+
+ /** [[DataProduct]] implementation for any [[Tuple9]] where each field has an implementation of `DataProduct`. */
+ implicit def tuple9DataProduct[
+ A : DataProduct,
+ B : DataProduct,
+ C : DataProduct,
+ D : DataProduct,
+ E : DataProduct,
+ F : DataProduct,
+ G : DataProduct,
+ H : DataProduct,
+ I : DataProduct]: DataProduct[(A, B, C, D, E, F, G, H, I)] =
+ new DataProduct[(A, B, C, D, E, F, G, H, I)] {
+ def dataIterator(tup: (A, B, C, D, E, F, G, H, I), path: String): Iterator[(Data, String)] = {
+ val dpa = implicitly[DataProduct[A]]
+ val dpb = implicitly[DataProduct[B]]
+ val dpc = implicitly[DataProduct[C]]
+ val dpd = implicitly[DataProduct[D]]
+ val dpe = implicitly[DataProduct[E]]
+ val dpf = implicitly[DataProduct[F]]
+ val dpg = implicitly[DataProduct[G]]
+ val dph = implicitly[DataProduct[H]]
+ val dpi = implicitly[DataProduct[I]]
+ val (a, b, c, d, e, f, g, h, i) = tup
+ dpa.dataIterator(a, s"$path._1") ++
+ dpb.dataIterator(b, s"$path._2") ++
+ dpc.dataIterator(c, s"$path._3") ++
+ dpd.dataIterator(d, s"$path._4") ++
+ dpe.dataIterator(e, s"$path._5") ++
+ dpf.dataIterator(f, s"$path._6") ++
+ dpg.dataIterator(g, s"$path._7") ++
+ dph.dataIterator(h, s"$path._8") ++
+ dpi.dataIterator(i, s"$path._9")
+ }
+ }
+
+ /** [[DataProduct]] implementation for any [[Tuple9]] where each field has an implementation of `DataProduct`. */
+ implicit def tuple10DataProduct[
+ A : DataProduct,
+ B : DataProduct,
+ C : DataProduct,
+ D : DataProduct,
+ E : DataProduct,
+ F : DataProduct,
+ G : DataProduct,
+ H : DataProduct,
+ I : DataProduct,
+ J : DataProduct]: DataProduct[(A, B, C, D, E, F, G, H, I, J)] =
+ new DataProduct[(A, B, C, D, E, F, G, H, I, J)] {
+ def dataIterator(tup: (A, B, C, D, E, F, G, H, I, J), path: String): Iterator[(Data, String)] = {
+ val dpa = implicitly[DataProduct[A]]
+ val dpb = implicitly[DataProduct[B]]
+ val dpc = implicitly[DataProduct[C]]
+ val dpd = implicitly[DataProduct[D]]
+ val dpe = implicitly[DataProduct[E]]
+ val dpf = implicitly[DataProduct[F]]
+ val dpg = implicitly[DataProduct[G]]
+ val dph = implicitly[DataProduct[H]]
+ val dpi = implicitly[DataProduct[I]]
+ val dpj = implicitly[DataProduct[J]]
+ val (a, b, c, d, e, f, g, h, i, j) = tup
+ dpa.dataIterator(a, s"$path._1") ++
+ dpb.dataIterator(b, s"$path._2") ++
+ dpc.dataIterator(c, s"$path._3") ++
+ dpd.dataIterator(d, s"$path._4") ++
+ dpe.dataIterator(e, s"$path._5") ++
+ dpf.dataIterator(f, s"$path._6") ++
+ dpg.dataIterator(g, s"$path._7") ++
+ dph.dataIterator(h, s"$path._8") ++
+ dpi.dataIterator(i, s"$path._9") ++
+ dpj.dataIterator(j, s"$path._10")
+ }
+ }
}
diff --git a/core/src/main/scala/chisel3/experimental/dataview/DataView.scala b/core/src/main/scala/chisel3/experimental/dataview/DataView.scala
index caf004c2..c17a5574 100644
--- a/core/src/main/scala/chisel3/experimental/dataview/DataView.scala
+++ b/core/src/main/scala/chisel3/experimental/dataview/DataView.scala
@@ -3,9 +3,12 @@
package chisel3.experimental.dataview
import chisel3._
-import chisel3.internal.sourceinfo.SourceInfo
-import scala.reflect.runtime.universe.WeakTypeTag
+import chisel3.experimental.DataMirror.internal.chiselTypeClone
+import chisel3.experimental.{HWTuple10, HWTuple2, HWTuple3, HWTuple4, HWTuple5, HWTuple6, HWTuple7, HWTuple8, HWTuple9}
+import chisel3.internal.sourceinfo.{SourceInfo, UnlocatableSourceInfo}
+import chisel3.ExplicitCompileOptions.Strict
+import scala.reflect.runtime.universe.WeakTypeTag
import annotation.implicitNotFound
@@ -132,9 +135,241 @@ object DataView {
case (b, a) => f(a, b).map(_.swap)
}
+ // ****************************** Built-in Implementations of DataView ******************************
+ // Sort of the "Standard library" implementations
+
/** All Chisel Data are viewable as their own type */
implicit def identityView[A <: Data](implicit sourceInfo: SourceInfo): DataView[A, A] =
DataView[A, A](chiselTypeOf.apply, { case (x, y) => (x, y) })
+
+ /** Provides `DataView[Seq[A], Vec[B]]` for all `A` such that there exists `DataView[A, B]` */
+ implicit def seqDataView[A : DataProduct, B <: Data](implicit dv: DataView[A, B], sourceInfo: SourceInfo): DataView[Seq[A], Vec[B]] = {
+ // TODO this would need a better way to determine the prototype for the Vec
+ DataView.mapping[Seq[A], Vec[B]](
+ xs => Vec(xs.size, chiselTypeClone(xs.head.viewAs[B]))(sourceInfo, Strict), // xs.head is not correct in general
+ { case (s, v) => s.zip(v).map { case (a, b) => a.viewAs[B] -> b } }
+ )
+ }
+
+ /** Provides implementations of [[DataView]] for [[Tuple2]] to [[HWTuple2]] */
+ implicit def tuple2DataView[T1 : DataProduct, T2 : DataProduct, V1 <: Data, V2 <: Data](
+ implicit v1: DataView[T1, V1], v2: DataView[T2, V2], sourceInfo: SourceInfo
+ ): DataView[(T1, T2), HWTuple2[V1, V2]] =
+ DataView.mapping(
+ { case (a, b) => new HWTuple2(a.viewAs[V1].cloneType, b.viewAs[V2].cloneType)},
+ { case ((a, b), hwt) =>
+ Seq(a.viewAs[V1] -> hwt._1,
+ b.viewAs[V2] -> hwt._2)
+ }
+ )
+
+ /** Provides implementations of [[DataView]] for [[Tuple3]] to [[HWTuple3]] */
+ implicit def tuple3DataView[
+ T1 : DataProduct, T2 : DataProduct, T3 : DataProduct,
+ V1 <: Data, V2 <: Data, V3 <: Data
+ ](
+ implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3], sourceInfo: SourceInfo
+ ): DataView[(T1, T2, T3), HWTuple3[V1, V2, V3]] =
+ DataView.mapping(
+ { case (a, b, c) => new HWTuple3(a.viewAs[V1].cloneType, b.viewAs[V2].cloneType, c.viewAs[V3].cloneType)},
+ { case ((a, b, c), hwt) =>
+ Seq(a.viewAs[V1] -> hwt._1,
+ b.viewAs[V2] -> hwt._2,
+ c.viewAs[V3] -> hwt._3)
+ }
+ )
+
+ /** Provides implementations of [[DataView]] for [[Tuple4]] to [[HWTuple4]] */
+ implicit def tuple4DataView[
+ T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, T4 : DataProduct,
+ V1 <: Data, V2 <: Data, V3 <: Data, V4 <: Data
+ ](
+ implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3], v4: DataView[T4, V4], sourceInfo: SourceInfo
+ ): DataView[(T1, T2, T3, T4), HWTuple4[V1, V2, V3, V4]] =
+ DataView.mapping(
+ { case (a, b, c, d) =>
+ new HWTuple4(a.viewAs[V1].cloneType, b.viewAs[V2].cloneType, c.viewAs[V3].cloneType, d.viewAs[V4].cloneType
+ )},
+ { case ((a, b, c, d), hwt) =>
+ Seq(a.viewAs[V1] -> hwt._1,
+ b.viewAs[V2] -> hwt._2,
+ c.viewAs[V3] -> hwt._3,
+ d.viewAs[V4] -> hwt._4)
+ }
+ )
+
+ /** Provides implementations of [[DataView]] for [[Tuple5]] to [[HWTuple5]] */
+ implicit def tuple5DataView[
+ T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, T4 : DataProduct, T5 : DataProduct,
+ V1 <: Data, V2 <: Data, V3 <: Data, V4 <: Data, V5 <: Data
+ ](
+ implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3], v4: DataView[T4, V4], v5: DataView[T5, V5], sourceInfo: SourceInfo
+ ): DataView[(T1, T2, T3, T4, T5), HWTuple5[V1, V2, V3, V4, V5]] = {
+ DataView.mapping(
+ { case tup: Tuple5[T1, T2, T3, T4, T5] =>
+ val (a, b, c, d, e) = tup
+ new HWTuple5(a.viewAs[V1].cloneType, b.viewAs[V2].cloneType, c.viewAs[V3].cloneType, d.viewAs[V4].cloneType,
+ e.viewAs[V5].cloneType
+ )
+ },
+ { case ((a, b, c, d, e), hwt) =>
+ Seq(a.viewAs[V1] -> hwt._1,
+ b.viewAs[V2] -> hwt._2,
+ c.viewAs[V3] -> hwt._3,
+ d.viewAs[V4] -> hwt._4,
+ e.viewAs[V5] -> hwt._5)
+ }
+ )
+ }
+
+ /** Provides implementations of [[DataView]] for [[Tuple6]] to [[HWTuple6]] */
+ implicit def tuple6DataView[
+ T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, T4 : DataProduct, T5 : DataProduct,
+ T6 : DataProduct,
+ V1 <: Data, V2 <: Data, V3 <: Data, V4 <: Data, V5 <: Data,
+ V6 <: Data
+ ](
+ implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3], v4: DataView[T4, V4],
+ v5: DataView[T5, V5], v6: DataView[T6, V6],
+ sourceInfo: SourceInfo
+ ): DataView[(T1, T2, T3, T4, T5, T6), HWTuple6[V1, V2, V3, V4, V5, V6]] =
+ DataView.mapping(
+ { case (a, b, c, d, e, f) =>
+ new HWTuple6(a.viewAs[V1].cloneType, b.viewAs[V2].cloneType, c.viewAs[V3].cloneType, d.viewAs[V4].cloneType,
+ e.viewAs[V5].cloneType, f.viewAs[V6].cloneType
+ )
+ },
+ { case ((a, b, c, d, e, f), hwt) =>
+ Seq(a.viewAs[V1] -> hwt._1,
+ b.viewAs[V2] -> hwt._2,
+ c.viewAs[V3] -> hwt._3,
+ d.viewAs[V4] -> hwt._4,
+ e.viewAs[V5] -> hwt._5,
+ f.viewAs[V6] -> hwt._6)
+ }
+ )
+
+ /** Provides implementations of [[DataView]] for [[Tuple7]] to [[HWTuple7]] */
+ implicit def tuple7DataView[
+ T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, T4 : DataProduct, T5 : DataProduct,
+ T6 : DataProduct, T7 : DataProduct,
+ V1 <: Data, V2 <: Data, V3 <: Data, V4 <: Data, V5 <: Data,
+ V6 <: Data, V7 <: Data
+ ](
+ implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3], v4: DataView[T4, V4],
+ v5: DataView[T5, V5], v6: DataView[T6, V6], v7: DataView[T7, V7],
+ sourceInfo: SourceInfo
+ ): DataView[(T1, T2, T3, T4, T5, T6, T7), HWTuple7[V1, V2, V3, V4, V5, V6, V7]] =
+ DataView.mapping(
+ { case (a, b, c, d, e, f, g) =>
+ new HWTuple7(a.viewAs[V1].cloneType, b.viewAs[V2].cloneType, c.viewAs[V3].cloneType, d.viewAs[V4].cloneType,
+ e.viewAs[V5].cloneType, f.viewAs[V6].cloneType, g.viewAs[V7].cloneType
+ )
+ },
+ { case ((a, b, c, d, e, f, g), hwt) =>
+ Seq(a.viewAs[V1] -> hwt._1,
+ b.viewAs[V2] -> hwt._2,
+ c.viewAs[V3] -> hwt._3,
+ d.viewAs[V4] -> hwt._4,
+ e.viewAs[V5] -> hwt._5,
+ f.viewAs[V6] -> hwt._6,
+ g.viewAs[V7] -> hwt._7)
+ }
+ )
+
+ /** Provides implementations of [[DataView]] for [[Tuple8]] to [[HWTuple8]] */
+ implicit def tuple8DataView[
+ T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, T4 : DataProduct, T5 : DataProduct,
+ T6 : DataProduct, T7 : DataProduct, T8 : DataProduct,
+ V1 <: Data, V2 <: Data, V3 <: Data, V4 <: Data, V5 <: Data,
+ V6 <: Data, V7 <: Data, V8 <: Data
+ ](
+ implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3], v4: DataView[T4, V4],
+ v5: DataView[T5, V5], v6: DataView[T6, V6], v7: DataView[T7, V7], v8: DataView[T8, V8],
+ sourceInfo: SourceInfo
+ ): DataView[(T1, T2, T3, T4, T5, T6, T7, T8), HWTuple8[V1, V2, V3, V4, V5, V6, V7, V8]] =
+ DataView.mapping(
+ { case (a, b, c, d, e, f, g, h) =>
+ new HWTuple8(a.viewAs[V1].cloneType, b.viewAs[V2].cloneType, c.viewAs[V3].cloneType, d.viewAs[V4].cloneType,
+ e.viewAs[V5].cloneType, f.viewAs[V6].cloneType, g.viewAs[V7].cloneType, h.viewAs[V8].cloneType
+ )
+ },
+ { case ((a, b, c, d, e, f, g, h), hwt) =>
+ Seq(a.viewAs[V1] -> hwt._1,
+ b.viewAs[V2] -> hwt._2,
+ c.viewAs[V3] -> hwt._3,
+ d.viewAs[V4] -> hwt._4,
+ e.viewAs[V5] -> hwt._5,
+ f.viewAs[V6] -> hwt._6,
+ g.viewAs[V7] -> hwt._7,
+ h.viewAs[V8] -> hwt._8)
+ }
+ )
+
+ /** Provides implementations of [[DataView]] for [[Tuple9]] to [[HWTuple9]] */
+ implicit def tuple9DataView[
+ T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, T4 : DataProduct, T5 : DataProduct,
+ T6 : DataProduct, T7 : DataProduct, T8 : DataProduct, T9 : DataProduct,
+ V1 <: Data, V2 <: Data, V3 <: Data, V4 <: Data, V5 <: Data,
+ V6 <: Data, V7 <: Data, V8 <: Data, V9 <: Data
+ ](
+ implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3], v4: DataView[T4, V4],
+ v5: DataView[T5, V5], v6: DataView[T6, V6], v7: DataView[T7, V7], v8: DataView[T8, V8],
+ v9: DataView[T9, V9],
+ sourceInfo: SourceInfo
+ ): DataView[(T1, T2, T3, T4, T5, T6, T7, T8, T9), HWTuple9[V1, V2, V3, V4, V5, V6, V7, V8, V9]] =
+ DataView.mapping(
+ { case (a, b, c, d, e, f, g, h, i) =>
+ new HWTuple9(a.viewAs[V1].cloneType, b.viewAs[V2].cloneType, c.viewAs[V3].cloneType, d.viewAs[V4].cloneType,
+ e.viewAs[V5].cloneType, f.viewAs[V6].cloneType, g.viewAs[V7].cloneType, h.viewAs[V8].cloneType,
+ i.viewAs[V9].cloneType
+ )
+ },
+ { case ((a, b, c, d, e, f, g, h, i), hwt) =>
+ Seq(a.viewAs[V1] -> hwt._1,
+ b.viewAs[V2] -> hwt._2,
+ c.viewAs[V3] -> hwt._3,
+ d.viewAs[V4] -> hwt._4,
+ e.viewAs[V5] -> hwt._5,
+ f.viewAs[V6] -> hwt._6,
+ g.viewAs[V7] -> hwt._7,
+ h.viewAs[V8] -> hwt._8,
+ i.viewAs[V9] -> hwt._9)
+ }
+ )
+
+ /** Provides implementations of [[DataView]] for [[Tuple10]] to [[HWTuple10]] */
+ implicit def tuple10DataView[
+ T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, T4 : DataProduct, T5 : DataProduct,
+ T6 : DataProduct, T7 : DataProduct, T8 : DataProduct, T9 : DataProduct, T10 : DataProduct,
+ V1 <: Data, V2 <: Data, V3 <: Data, V4 <: Data, V5 <: Data,
+ V6 <: Data, V7 <: Data, V8 <: Data, V9 <: Data, V10 <: Data
+ ](
+ implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3], v4: DataView[T4, V4],
+ v5: DataView[T5, V5], v6: DataView[T6, V6], v7: DataView[T7, V7], v8: DataView[T8, V8],
+ v9: DataView[T9, V9], v10: DataView[T10, V10],
+ sourceInfo: SourceInfo
+ ): DataView[(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10), HWTuple10[V1, V2, V3, V4, V5, V6, V7, V8, V9, V10]] =
+ DataView.mapping(
+ { case (a, b, c, d, e, f, g, h, i, j) =>
+ new HWTuple10(a.viewAs[V1].cloneType, b.viewAs[V2].cloneType, c.viewAs[V3].cloneType, d.viewAs[V4].cloneType,
+ e.viewAs[V5].cloneType, f.viewAs[V6].cloneType, g.viewAs[V7].cloneType, h.viewAs[V8].cloneType,
+ i.viewAs[V9].cloneType, j.viewAs[V10].cloneType
+ )
+ },
+ { case ((a, b, c, d, e, f, g, h, i, j), hwt) =>
+ Seq(a.viewAs[V1] -> hwt._1,
+ b.viewAs[V2] -> hwt._2,
+ c.viewAs[V3] -> hwt._3,
+ d.viewAs[V4] -> hwt._4,
+ e.viewAs[V5] -> hwt._5,
+ f.viewAs[V6] -> hwt._6,
+ g.viewAs[V7] -> hwt._7,
+ h.viewAs[V8] -> hwt._8,
+ i.viewAs[V9] -> hwt._9,
+ j.viewAs[V10] -> hwt._10)
+ }
+ )
}
/** Factory methods for constructing non-total [[DataView]]s */
diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala
index 0cc3d131..c7b51072 100644
--- a/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala
+++ b/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala
@@ -18,13 +18,9 @@ import firrtl.annotations.{IsModule, ModuleTarget}
*
* These definitions are then used to create multiple [[Instance]]s.
*
- * @param cloned The internal representation of the instance, which may be either be directly the object, or a clone of an object
+ * @param underlying The internal representation of the definition, which may be either be directly the object, or a clone of an object
*/
-case class Definition[+A] private[chisel3] (private[chisel3] cloned: Either[A, IsClone[A]]) extends IsLookupable {
- private[chisel3] def proto: A = cloned match {
- case Left(value: A) => value
- case Right(i: IsClone[A]) => i._proto
- }
+final case class Definition[+A] private[chisel3] (private[chisel3] underlying: Underlying[A]) extends IsLookupable with SealedHierarchy[A] {
/** Used by Chisel's internal macros. DO NOT USE in your normal Chisel code!!!
* Instead, mark the field you are accessing with [[@public]]
*
@@ -43,20 +39,20 @@ case class Definition[+A] private[chisel3] (private[chisel3] cloned: Either[A, I
lookup.definitionLookup(that, this)
}
- /** Updated by calls to [[apply]], to avoid recloning returned Data's */
- private [chisel3] val cache = HashMap[Data, Data]()
-
-
/** @return the context of any Data's return from inside the instance */
private[chisel3] def getInnerDataContext: Option[BaseModule] = proto match {
case value: BaseModule =>
- val newChild = Module.do_apply(new internal.BaseModule.DefinitionClone(value))(chisel3.internal.sourceinfo.UnlocatableSourceInfo, chisel3.ExplicitCompileOptions.Strict)
+ val newChild = Module.do_pseudo_apply(new internal.BaseModule.DefinitionClone(value))(chisel3.internal.sourceinfo.UnlocatableSourceInfo, chisel3.ExplicitCompileOptions.Strict)
newChild._circuit = value._circuit.orElse(Some(value))
newChild._parent = None
Some(newChild)
case value: IsInstantiable => None
}
+ override def toDefinition: Definition[A] = this
+ override def toInstance: Instance[A] = new Instance(underlying)
+
+
}
/** Factory methods for constructing [[Definition]]s */
@@ -90,11 +86,12 @@ object Definition extends SourceInfoDoc {
val dynamicContext = new DynamicContext(Nil)
Builder.globalNamespace.copyTo(dynamicContext.globalNamespace)
dynamicContext.inDefinition = true
- val (ir, module) = Builder.build(Module(proto), dynamicContext)
+ val (ir, module) = Builder.build(Module(proto), dynamicContext, false)
Builder.components ++= ir.components
Builder.annotations ++= ir.annotations
module._circuit = Builder.currentModule
dynamicContext.globalNamespace.copyTo(Builder.globalNamespace)
- new Definition(Left(module))
+ new Definition(Proto(module))
}
+
}
diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala
new file mode 100644
index 00000000..503e437b
--- /dev/null
+++ b/core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: Apache-2.0
+
+package chisel3.experimental.hierarchy
+
+import chisel3._
+import scala.collection.mutable.{HashMap, HashSet}
+import scala.reflect.runtime.universe.TypeTag
+import chisel3.internal.BaseModule.IsClone
+import chisel3.experimental.BaseModule
+import _root_.firrtl.annotations.IsModule
+import scala.annotation.implicitNotFound
+
+/** Super-trait for Instance and Definition
+ *
+ * Enables writing functions which are Instance/Definition agnostic
+ */
+sealed trait Hierarchy[+A] {
+ private[chisel3] def underlying: Underlying[A]
+ private[chisel3] def proto: A = underlying match {
+ case Proto(value: A) => value
+ case Clone(i: IsClone[A]) => i.getProto
+ }
+
+ /** Updated by calls to [[_lookup]], to avoid recloning returned Data's */
+ private[chisel3] val cache = HashMap[Data, Data]()
+ private[chisel3] def getInnerDataContext: Option[BaseModule]
+
+ /** Determine whether underlying proto is of type provided.
+ *
+ * @note IMPORTANT: this function requires summoning a TypeTag[B], which will fail if B is an inner class.
+ * @note IMPORTANT: this function IGNORES type parameters, akin to normal type erasure.
+ * @note IMPORTANT: this function relies on Java reflection for underlying proto, but Scala reflection for provided type
+ *
+ * E.g. isA[List[Int]] will return true, even if underlying proto is of type List[String]
+ * @return Whether underlying proto is of provided type (with caveats outlined above)
+ */
+ def isA[B : TypeTag]: Boolean = {
+ val tptag = implicitly[TypeTag[B]]
+ val name = tptag.tpe.toString
+ inBaseClasses(name)
+ }
+
+
+ // This code handles a special-case where, within an mdoc context, the type returned from
+ // scala reflection (typetag) looks different than when returned from java reflection.
+ // This function detects this case and reshapes the string to match.
+ private def modifyReplString(clz: String): String = {
+ if(clz != null) {
+ clz.split('.').toList match {
+ case "repl" :: "MdocSession" :: app :: rest => s"$app.this." + rest.mkString(".")
+ case other => clz
+ }
+ } else clz
+ }
+ private lazy val superClasses = calculateSuperClasses(proto.getClass())
+ private def calculateSuperClasses(clz: Class[_]): Set[String] = {
+ if(clz != null) {
+ Set(modifyReplString(clz.getCanonicalName())) ++
+ clz.getInterfaces().flatMap(i => calculateSuperClasses(i)) ++
+ calculateSuperClasses(clz.getSuperclass())
+ } else {
+ Set.empty[String]
+ }
+ }
+ private def inBaseClasses(clz: String): Boolean = superClasses.contains(clz)
+
+
+ /** Used by Chisel's internal macros. DO NOT USE in your normal Chisel code!!!
+ * Instead, mark the field you are accessing with [[@public]]
+ *
+ * Given a selector function (that) which selects a member from the original, return the
+ * corresponding member from the hierarchy.
+ *
+ * Our @instantiable and @public macros generate the calls to this apply method
+ *
+ * By calling this function, we summon the proper Lookupable typeclass from our implicit scope.
+ *
+ * @param that a user-specified lookup function
+ * @param lookup typeclass which contains the correct lookup function, based on the types of A and B
+ * @param macroGenerated a value created in the macro, to make it harder for users to use this API
+ */
+ def _lookup[B, C](that: A => B)(implicit lookup: Lookupable[B], macroGenerated: chisel3.internal.MacroGenerated): lookup.C
+
+ /** @return Return the underlying Definition[A] of this Hierarchy[A] */
+ def toDefinition: Definition[A]
+
+ /** @return Convert this Hierarchy[A] as a top-level Instance[A] */
+ def toInstance: Instance[A]
+}
+
+// Used to effectively seal Hierarchy, without requiring Definition and Instance to be in this file.
+private[chisel3] trait SealedHierarchy[+A] extends Hierarchy[A]
+
+object Hierarchy {
+ implicit class HierarchyBaseModuleExtensions[T <: BaseModule](i: Hierarchy[T]) {
+ /** Returns the toTarget of this hierarchy
+ * @return target of this hierarchy
+ */
+ def toTarget: IsModule = i match {
+ case d: Definition[T] => new Definition.DefinitionBaseModuleExtensions(d).toTarget
+ case i: Instance[T] => new Instance.InstanceBaseModuleExtensions(i).toTarget
+ }
+
+ /** Returns the toAbsoluteTarget of this hierarchy
+ * @return absoluteTarget of this Hierarchy
+ */
+ def toAbsoluteTarget: IsModule = i match {
+ case d: Definition[T] => new Definition.DefinitionBaseModuleExtensions(d).toAbsoluteTarget
+ case i: Instance[T] => new Instance.InstanceBaseModuleExtensions(i).toAbsoluteTarget
+ }
+ }
+}
diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala
index 9b17bfce..97b62c23 100644
--- a/core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala
+++ b/core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala
@@ -14,38 +14,29 @@ import firrtl.annotations.IsModule
* Represents a unique instance of type [[A]] which are marked as @instantiable
* Can be created using Instance.apply method.
*
- * @param cloned The internal representation of the instance, which may be either be directly the object, or a clone of an object
+ * @param underlying The internal representation of the instance, which may be either be directly the object, or a clone of an object
*/
-case class Instance[+A] private [chisel3] (private[chisel3] cloned: Either[A, IsClone[A]]) {
-
- /** Returns the original object which is instantiated here.
- * If this is an instance of a clone, return that clone's original proto
- *
- * @return the original object which was instantiated
- */
- private[chisel3] def proto: A = cloned match {
- case Left(value: A) => value
- case Right(i: IsClone[A]) => i._proto
+final case class Instance[+A] private [chisel3] (private[chisel3] underlying: Underlying[A]) extends SealedHierarchy[A] {
+ underlying match {
+ case Proto(p: IsClone[_]) => chisel3.internal.throwException("Cannot have a Proto with a clone!")
+ case other => //Ok
}
/** @return the context of any Data's return from inside the instance */
- private[chisel3] def getInnerDataContext: Option[BaseModule] = cloned match {
- case Left(value: BaseModule) => Some(value)
- case Left(value: IsInstantiable) => None
- case Right(i: BaseModule) => Some(i)
- case Right(i: InstantiableClone[_]) => i._parent
+ private[chisel3] def getInnerDataContext: Option[BaseModule] = underlying match {
+ case Proto(value: BaseModule) => Some(value)
+ case Proto(value: IsInstantiable) => None
+ case Clone(i: BaseModule) => Some(i)
+ case Clone(i: InstantiableClone[_]) => i.getInnerContext
}
/** @return the context this instance. Note that for non-module clones, getInnerDataContext will be the same as getClonedParent */
- private[chisel3] def getClonedParent: Option[BaseModule] = cloned match {
- case Left(value: BaseModule) => value._parent
- case Right(i: BaseModule) => i._parent
- case Right(i: InstantiableClone[_]) => i._parent
+ private[chisel3] def getClonedParent: Option[BaseModule] = underlying match {
+ case Proto(value: BaseModule) => value._parent
+ case Clone(i: BaseModule) => i._parent
+ case Clone(i: InstantiableClone[_]) => i.getInnerContext
}
- /** Updated by calls to [[apply]], to avoid recloning returned Data's */
- private [chisel3] val cache = HashMap[Data, Data]()
-
/** Used by Chisel's internal macros. DO NOT USE in your normal Chisel code!!!
* Instead, mark the field you are accessing with [[@public]]
*
@@ -65,7 +56,8 @@ case class Instance[+A] private [chisel3] (private[chisel3] cloned: Either[A, Is
}
/** Returns the definition of this Instance */
- def toDefinition: Definition[A] = new Definition(Left(proto))
+ override def toDefinition: Definition[A] = new Definition(Proto(proto))
+ override def toInstance: Instance[A] = this
}
@@ -75,17 +67,17 @@ object Instance extends SourceInfoDoc {
/** If this is an instance of a Module, returns the toTarget of this instance
* @return target of this instance
*/
- def toTarget: IsModule = i.cloned match {
- case Left(x: BaseModule) => x.getTarget
- case Right(x: IsClone[_] with BaseModule) => x.getTarget
+ def toTarget: IsModule = i.underlying match {
+ case Proto(x: BaseModule) => x.getTarget
+ case Clone(x: IsClone[_] with BaseModule) => x.getTarget
}
/** If this is an instance of a Module, returns the toAbsoluteTarget of this instance
* @return absoluteTarget of this instance
*/
- def toAbsoluteTarget: IsModule = i.cloned match {
- case Left(x) => x.toAbsoluteTarget
- case Right(x: IsClone[_] with BaseModule) => x.toAbsoluteTarget
+ def toAbsoluteTarget: IsModule = i.underlying match {
+ case Proto(x) => x.toAbsoluteTarget
+ case Clone(x: IsClone[_] with BaseModule) => x.toAbsoluteTarget
}
}
@@ -105,7 +97,7 @@ object Instance extends SourceInfoDoc {
val ports = experimental.CloneModuleAsRecord(definition.proto)
val clone = ports._parent.get.asInstanceOf[ModuleClone[T]]
clone._madeFromDefinition = true
- new Instance(Right(clone))
+ new Instance(Clone(clone))
}
}
diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/IsInstantiable.scala b/core/src/main/scala/chisel3/experimental/hierarchy/IsInstantiable.scala
index 26ba0286..4f3c2d42 100644
--- a/core/src/main/scala/chisel3/experimental/hierarchy/IsInstantiable.scala
+++ b/core/src/main/scala/chisel3/experimental/hierarchy/IsInstantiable.scala
@@ -12,6 +12,6 @@ trait IsInstantiable
object IsInstantiable {
implicit class IsInstantiableExtensions[T <: IsInstantiable](i: T) {
- def toInstance: Instance[T] = new Instance(Left(i))
+ def toInstance: Instance[T] = new Instance(Proto(i))
}
}
diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/LibraryHooks.scala b/core/src/main/scala/chisel3/experimental/hierarchy/LibraryHooks.scala
new file mode 100644
index 00000000..c16cc633
--- /dev/null
+++ b/core/src/main/scala/chisel3/experimental/hierarchy/LibraryHooks.scala
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: Apache-2.0
+
+package chisel3.experimental.hierarchy
+
+import scala.annotation.implicitNotFound
+
+@implicitNotFound("These functions are only for building hierarchy-compatible Chisel libraries! Users beware!")
+// DO NOT extend unless you know what you are doing!!!!!! Not for the casual user!
+trait InsideHierarchyLibraryExtension
+
+// Collection of public functions to give non-core-Chisel libraries the ability to build integrations with
+// the experimental hierarchy package
+object LibraryHooks {
+
+ /** Builds a new instance given a definition and function to create a new instance-specific Underlying, from the
+ * definition's Underlying
+ * @note Implicitly requires being inside a Hierarchy Library Extension
+ */
+ def buildInstance[A](definition: Definition[A],
+ createUnderlying: Underlying[A] => Underlying[A]
+ )(implicit inside: InsideHierarchyLibraryExtension): Instance[A] = {
+ new Instance(createUnderlying(definition.underlying))
+ }
+
+ /** Builds a new definition given an Underlying implementation
+ * @note Implicitly requires being inside a Hierarchy Library Extension
+ */
+ def buildDefinition[A](underlying: Underlying[A])(implicit inside: InsideHierarchyLibraryExtension): Definition[A] = {
+ new Definition(underlying)
+ }
+}
diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala
index b9617723..ff4d676c 100644
--- a/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala
+++ b/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala
@@ -19,7 +19,7 @@ import chisel3.internal.{AggregateViewBinding, Builder, ChildBinding, ViewBindin
*/
@implicitNotFound("@public is only legal within a class marked @instantiable and only on vals of type" +
" Data, BaseModule, IsInstantiable, IsLookupable, or Instance[_], or in an Iterable or Option")
-sealed trait Lookupable[-B] {
+trait Lookupable[-B] {
type C // Return type of the lookup
/** Function called to modify the returned value of type B from A, into C
*
@@ -36,9 +36,11 @@ sealed trait Lookupable[-B] {
* @return
*/
def definitionLookup[A](that: A => B, definition: Definition[A]): C
+ protected def getProto[A](h: Hierarchy[A]): A = h.proto
+ protected def getUnderlying[A](h: Hierarchy[A]): Underlying[A] = h.underlying
}
-private[chisel3] object Lookupable {
+object Lookupable {
/** Clones a data and sets its internal references to its parent module to be in a new context.
*
@@ -52,10 +54,10 @@ private[chisel3] object Lookupable {
data._parent match {
case None => data
case Some(parent) =>
- val newParent = cloneModuleToContext(Left(parent), context)
+ val newParent = cloneModuleToContext(Proto(parent), context)
newParent match {
- case Left(p) if p == parent => data
- case Right(m: BaseModule) =>
+ case Proto(p) if p == parent => data
+ case Clone(m: BaseModule) =>
val newChild = data.cloneTypeFull
newChild.setRef(data.getRef, true)
newChild.bind(internal.CrossModuleBinding)
@@ -145,7 +147,7 @@ private[chisel3] object Lookupable {
val result = data.cloneTypeFull
- // We have to lookup the target(s) of the view since they may need to be cloned into the current context
+ // We have to lookup the target(s) of the view since they may need to be underlying into the current context
val newBinding = data.topBinding match {
case ViewBinding(target) => ViewBinding(lookupData(reify(target)))
case avb @ AggregateViewBinding(map, targetOpt) => data match {
@@ -199,51 +201,51 @@ private[chisel3] object Lookupable {
* This function effectively recurses up the parents of module to find whether:
* (1) A parent is already in the context; then we do nothing and return module
* (2) A parent is in a different clone of the context; then we clone all the parents up
- * to that parent and set their parents to be in this cloned context
+ * to that parent and set their parents to be in this underlying context
* (3) A parent has no root; in that case, we do nothing and return the module.
*
- * @param module original or clone to be cloned into a new context
+ * @param module original or clone to be underlying into a new context
* @param context new context
* @return original or clone in the new context
*/
- private[chisel3] def cloneModuleToContext[T <: BaseModule](module: Either[T, IsClone[T]], context: BaseModule)
- (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Either[T, IsClone[T]] = {
+ private[chisel3] def cloneModuleToContext[T <: BaseModule](module: Underlying[T], context: BaseModule)
+ (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Underlying[T] = {
// Recursive call
- def rec[A <: BaseModule](m: A): Either[A, IsClone[A]] = {
- def clone(x: A, p: Option[BaseModule], name: () => String): Either[A, IsClone[A]] = {
- val newChild = Module.do_apply(new internal.BaseModule.InstanceClone(x, name))
+ def rec[A <: BaseModule](m: A): Underlying[A] = {
+ def clone(x: A, p: Option[BaseModule], name: () => String): Underlying[A] = {
+ val newChild = Module.do_pseudo_apply(new internal.BaseModule.InstanceClone(x, name))
newChild._parent = p
- Right(newChild)
+ Clone(newChild)
}
(m, context) match {
- case (c, ctx) if ctx == c => Left(c)
- case (c, ctx: IsClone[_]) if ctx.isACloneOf(c) => Right(ctx.asInstanceOf[IsClone[A]])
- case (c, ctx) if c._parent.isEmpty => Left(c)
+ case (c, ctx) if ctx == c => Proto(c)
+ case (c, ctx: IsClone[_]) if ctx.hasSameProto(c) => Clone(ctx.asInstanceOf[IsClone[A]])
+ case (c, ctx) if c._parent.isEmpty => Proto(c)
case (_, _) =>
- cloneModuleToContext(Left(m._parent.get), context) match {
- case Left(p) => Left(m)
- case Right(p: BaseModule) =>
+ cloneModuleToContext(Proto(m._parent.get), context) match {
+ case Proto(p) => Proto(m)
+ case Clone(p: BaseModule) =>
clone(m, Some(p), () => m.instanceName)
}
}
}
module match {
- case Left(m) => rec(m)
- case Right(m: ModuleClone[_]) =>
+ case Proto(m) => rec(m)
+ case Clone(m: ModuleClone[_]) =>
rec(m) match {
- case Left(mx) => Right(mx)
- case Right(i: InstanceClone[_]) =>
- val newChild = Module.do_apply(new InstanceClone(m._proto, () => m.instanceName))
+ case Proto(mx) => Clone(mx)
+ case Clone(i: InstanceClone[_]) =>
+ val newChild = Module.do_pseudo_apply(new InstanceClone(m.getProto, () => m.instanceName))
newChild._parent = i._parent
- Right(newChild)
+ Clone(newChild)
}
- case Right(m: InstanceClone[_]) =>
+ case Clone(m: InstanceClone[_]) =>
rec(m) match {
- case Left(mx) => Right(mx)
- case Right(i: InstanceClone[_]) =>
- val newChild = Module.do_apply(new InstanceClone(m._proto, () => m.instanceName))
+ case Proto(mx) => Clone(mx)
+ case Clone(i: InstanceClone[_]) =>
+ val newChild = Module.do_pseudo_apply(new InstanceClone(m.getProto, () => m.instanceName))
newChild._parent = i._parent
- Right(newChild)
+ Clone(newChild)
}
}
}
@@ -259,14 +261,14 @@ private[chisel3] object Lookupable {
type C = Instance[B]
def definitionLookup[A](that: A => Instance[B], definition: Definition[A]): C = {
val ret = that(definition.proto)
- new Instance(cloneModuleToContext(ret.cloned, definition.getInnerDataContext.get))
+ new Instance(cloneModuleToContext(ret.underlying, definition.getInnerDataContext.get))
}
def instanceLookup[A](that: A => Instance[B], instance: Instance[A]): C = {
val ret = that(instance.proto)
- instance.cloned match {
+ instance.underlying match {
// If instance is just a normal module, no changing of context is necessary
- case Left(_) => new Instance(ret.cloned)
- case Right(_) => new Instance(cloneModuleToContext(ret.cloned, instance.getInnerDataContext.get))
+ case Proto(_) => new Instance(ret.underlying)
+ case Clone(_) => new Instance(cloneModuleToContext(ret.underlying, instance.getInnerDataContext.get))
}
}
}
@@ -275,14 +277,14 @@ private[chisel3] object Lookupable {
type C = Instance[B]
def definitionLookup[A](that: A => B, definition: Definition[A]): C = {
val ret = that(definition.proto)
- new Instance(cloneModuleToContext(Left(ret), definition.getInnerDataContext.get))
+ new Instance(cloneModuleToContext(Proto(ret), definition.getInnerDataContext.get))
}
def instanceLookup[A](that: A => B, instance: Instance[A]): C = {
val ret = that(instance.proto)
- instance.cloned match {
+ instance.underlying match {
// If instance is just a normal module, no changing of context is necessary
- case Left(_) => new Instance(Left(ret))
- case Right(_) => new Instance(cloneModuleToContext(Left(ret), instance.getInnerDataContext.get))
+ case Proto(_) => new Instance(Proto(ret))
+ case Clone(_) => new Instance(cloneModuleToContext(Proto(ret), instance.getInnerDataContext.get))
}
}
}
@@ -299,9 +301,9 @@ private[chisel3] object Lookupable {
}
def instanceLookup[A](that: A => B, instance: Instance[A]): C = {
val ret = that(instance.proto)
- val ioMap: Option[Map[Data, Data]] = instance.cloned match {
- case Right(x: ModuleClone[_]) => Some(x.ioMap)
- case Left(x: BaseModule) => Some(x.getChiselPorts.map { case (_, data) => data -> data }.toMap)
+ val ioMap: Option[Map[Data, Data]] = instance.underlying match {
+ case Clone(x: ModuleClone[_]) => Some(x.ioMap)
+ case Proto(x: BaseModule) => Some(x.getChiselPorts.map { case (_, data) => data -> data }.toMap)
case _ => None
}
if (isView(ret)) {
@@ -342,15 +344,19 @@ private[chisel3] object Lookupable {
type C = Instance[B]
def definitionLookup[A](that: A => B, definition: Definition[A]): C = {
val ret = that(definition.proto)
- val cloned = new InstantiableClone(ret)
- cloned._parent = definition.getInnerDataContext
- new Instance(Right(cloned))
+ val underlying = new InstantiableClone[B] {
+ val getProto = ret
+ lazy val _innerContext = definition
+ }
+ new Instance(Clone(underlying))
}
def instanceLookup[A](that: A => B, instance: Instance[A]): C = {
val ret = that(instance.proto)
- val cloned = new InstantiableClone(ret)
- cloned._parent = instance.getInnerDataContext
- new Instance(Right(cloned))
+ val underlying = new InstantiableClone[B] {
+ val getProto = ret
+ lazy val _innerContext = instance
+ }
+ new Instance(Clone(underlying))
}
}
diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Underlying.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Underlying.scala
new file mode 100644
index 00000000..864cc8af
--- /dev/null
+++ b/core/src/main/scala/chisel3/experimental/hierarchy/Underlying.scala
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: Apache-2.0
+
+package chisel3.experimental.hierarchy
+
+import chisel3.internal.BaseModule.IsClone
+
+/** Represents the underlying implementation of a Definition or Instance */
+sealed trait Underlying[+T]
+
+/** A clone of a real implementation */
+final case class Clone[+T](isClone: IsClone[T]) extends Underlying[T]
+
+/** An actual implementation */
+final case class Proto[+T](proto: T) extends Underlying[T]
diff --git a/core/src/main/scala/chisel3/experimental/package.scala b/core/src/main/scala/chisel3/experimental/package.scala
index 8018159f..5397a1c3 100644
--- a/core/src/main/scala/chisel3/experimental/package.scala
+++ b/core/src/main/scala/chisel3/experimental/package.scala
@@ -2,7 +2,8 @@
package chisel3
-import chisel3.internal.NamedComponent
+import chisel3.ExplicitCompileOptions.Strict
+import chisel3.experimental.DataMirror.internal.chiselTypeClone
import chisel3.internal.sourceinfo.SourceInfo
/** Package for experimental features, which may have their API changed, be removed, etc.
@@ -167,8 +168,149 @@ package object experimental {
// Use to remove prefixes not in provided scope
val noPrefix = chisel3.internal.noPrefix
- /** Base simulation-only component. */
- abstract class BaseSim extends NamedComponent {
- _parent.foreach(_.addId(this))
+ // ****************************** Hardware equivalents of Scala Tuples ******************************
+ // These are intended to be used via DataView
+
+ /** [[Data]] equivalent of Scala's [[Tuple2]]
+ *
+ * Users may not instantiate this class directly. Instead they should use the implicit conversion from `Tuple2` in
+ * `chisel3.experimental.conversions`
+ */
+ final class HWTuple2[+A <: Data, +B <: Data] private[chisel3] (val _1: A, val _2: B) extends Bundle()(Strict) {
+ // Because this implementation exists in chisel3.core, it cannot compile with the plugin, so we implement the behavior manually
+ override protected def _usingPlugin: Boolean = true
+ override protected def _cloneTypeImpl: Bundle = new HWTuple2(chiselTypeClone(_1), chiselTypeClone(_2))
+ }
+
+ /** [[Data]] equivalent of Scala's [[Tuple3]]
+ *
+ * Users may not instantiate this class directly. Instead they should use the implicit conversion from `Tuple3` in
+ * `chisel3.experimental.conversions`
+ */
+ final class HWTuple3[+A <: Data, +B <: Data, +C <: Data] private[chisel3] (
+ val _1: A, val _2: B, val _3: C
+ ) extends Bundle()(Strict) {
+ // Because this implementation exists in chisel3.core, it cannot compile with the plugin, so we implement the behavior manually
+ override protected def _usingPlugin: Boolean = true
+ override protected def _cloneTypeImpl: Bundle = new HWTuple3(
+ chiselTypeClone(_1), chiselTypeClone(_2), chiselTypeClone(_3)
+ )
+ }
+
+ /** [[Data]] equivalent of Scala's [[Tuple4]]
+ *
+ * Users may not instantiate this class directly. Instead they should use the implicit conversion from `Tuple4` in
+ * `chisel3.experimental.conversions`
+ */
+ final class HWTuple4[+A <: Data, +B <: Data, +C <: Data, +D <: Data] private[chisel3] (
+ val _1: A, val _2: B, val _3: C, val _4: D
+ ) extends Bundle()(Strict) {
+ // Because this implementation exists in chisel3.core, it cannot compile with the plugin, so we implement the behavior manually
+ override protected def _usingPlugin: Boolean = true
+ override protected def _cloneTypeImpl: Bundle = new HWTuple4(
+ chiselTypeClone(_1), chiselTypeClone(_2), chiselTypeClone(_3), chiselTypeClone(_4)
+ )
+ }
+
+ /** [[Data]] equivalent of Scala's [[Tuple5]]
+ *
+ * Users may not instantiate this class directly. Instead they should use the implicit conversion from `Tuple5` in
+ * `chisel3.experimental.conversions`
+ */
+ final class HWTuple5[+A <: Data, +B <: Data, +C <: Data, +D <: Data, +E <: Data] private[chisel3] (
+ val _1: A, val _2: B, val _3: C, val _4: D, val _5: E
+ ) extends Bundle()(Strict) {
+ // Because this implementation exists in chisel3.core, it cannot compile with the plugin, so we implement the behavior manually
+ override protected def _usingPlugin: Boolean = true
+ override protected def _cloneTypeImpl: Bundle = new HWTuple5(
+ chiselTypeClone(_1), chiselTypeClone(_2), chiselTypeClone(_3), chiselTypeClone(_4), chiselTypeClone(_5)
+ )
+ }
+
+ /** [[Data]] equivalent of Scala's [[Tuple6]]
+ *
+ * Users may not instantiate this class directly. Instead they should use the implicit conversion from `Tuple6` in
+ * `chisel3.experimental.conversions`
+ */
+ final class HWTuple6[+A <: Data, +B <: Data, +C <: Data, +D <: Data, +E <: Data, +F <: Data] private[chisel3] (
+ val _1: A, val _2: B, val _3: C, val _4: D, val _5: E, val _6: F
+ ) extends Bundle()(Strict) {
+ // Because this implementation exists in chisel3.core, it cannot compile with the plugin, so we implement the behavior manually
+ override protected def _usingPlugin: Boolean = true
+ override protected def _cloneTypeImpl: Bundle = new HWTuple6(
+ chiselTypeClone(_1), chiselTypeClone(_2), chiselTypeClone(_3), chiselTypeClone(_4), chiselTypeClone(_5),
+ chiselTypeClone(_6)
+ )
+ }
+
+ /** [[Data]] equivalent of Scala's [[Tuple7]]
+ *
+ * Users may not instantiate this class directly. Instead they should use the implicit conversion from `Tuple7` in
+ * `chisel3.experimental.conversions`
+ */
+ final class HWTuple7[+A <: Data, +B <: Data, +C <: Data, +D <: Data, +E <: Data, +F <: Data, +G <: Data] private[chisel3] (
+ val _1: A, val _2: B, val _3: C, val _4: D, val _5: E, val _6: F, val _7: G
+ ) extends Bundle()(Strict) {
+ // Because this implementation exists in chisel3.core, it cannot compile with the plugin, so we implement the behavior manually
+ override protected def _usingPlugin: Boolean = true
+ override protected def _cloneTypeImpl: Bundle = new HWTuple7(
+ chiselTypeClone(_1), chiselTypeClone(_2), chiselTypeClone(_3), chiselTypeClone(_4), chiselTypeClone(_5),
+ chiselTypeClone(_6), chiselTypeClone(_7)
+ )
+ }
+
+ /** [[Data]] equivalent of Scala's [[Tuple8]]
+ *
+ * Users may not instantiate this class directly. Instead they should use the implicit conversion from `Tuple8` in
+ * `chisel3.experimental.conversions`
+ */
+ final class HWTuple8[
+ +A <: Data, +B <: Data, +C <: Data, +D <: Data, +E <: Data, +F <: Data, +G <: Data, +H <: Data
+ ] private[chisel3] (
+ val _1: A, val _2: B, val _3: C, val _4: D, val _5: E, val _6: F, val _7: G, val _8: H
+ ) extends Bundle()(Strict) {
+ // Because this implementation exists in chisel3.core, it cannot compile with the plugin, so we implement the behavior manually
+ override protected def _usingPlugin: Boolean = true
+ override protected def _cloneTypeImpl: Bundle = new HWTuple8(
+ chiselTypeClone(_1), chiselTypeClone(_2), chiselTypeClone(_3), chiselTypeClone(_4), chiselTypeClone(_5),
+ chiselTypeClone(_6), chiselTypeClone(_7), chiselTypeClone(_8)
+ )
+ }
+
+ /** [[Data]] equivalent of Scala's [[Tuple9]]
+ *
+ * Users may not instantiate this class directly. Instead they should use the implicit conversion from `Tuple9` in
+ * `chisel3.experimental.conversions`
+ */
+ final class HWTuple9[
+ +A <: Data, +B <: Data, +C <: Data, +D <: Data, +E <: Data, +F <: Data, +G <: Data, +H <: Data, +I <: Data
+ ] private[chisel3] (
+ val _1: A, val _2: B, val _3: C, val _4: D, val _5: E, val _6: F, val _7: G, val _8: H, val _9: I
+ ) extends Bundle()(Strict) {
+ // Because this implementation exists in chisel3.core, it cannot compile with the plugin, so we implement the behavior manually
+ override protected def _usingPlugin: Boolean = true
+ override protected def _cloneTypeImpl: Bundle = new HWTuple9(
+ chiselTypeClone(_1), chiselTypeClone(_2), chiselTypeClone(_3), chiselTypeClone(_4), chiselTypeClone(_5),
+ chiselTypeClone(_6), chiselTypeClone(_7), chiselTypeClone(_8), chiselTypeClone(_9)
+ )
+ }
+
+
+ /** [[Data]] equivalent of Scala's [[Tuple9]]
+ *
+ * Users may not instantiate this class directly. Instead they should use the implicit conversion from `Tuple9` in
+ * `chisel3.experimental.conversions`
+ */
+ final class HWTuple10[
+ +A <: Data, +B <: Data, +C <: Data, +D <: Data, +E <: Data, +F <: Data, +G <: Data, +H <: Data, +I <: Data, +J <: Data
+ ] private[chisel3] (
+ val _1: A, val _2: B, val _3: C, val _4: D, val _5: E, val _6: F, val _7: G, val _8: H, val _9: I, val _10: J
+ ) extends Bundle()(Strict) {
+ // Because this implementation exists in chisel3.core, it cannot compile with the plugin, so we implement the behavior manually
+ override protected def _usingPlugin: Boolean = true
+ override protected def _cloneTypeImpl: Bundle = new HWTuple10(
+ chiselTypeClone(_1), chiselTypeClone(_2), chiselTypeClone(_3), chiselTypeClone(_4), chiselTypeClone(_5),
+ chiselTypeClone(_6), chiselTypeClone(_7), chiselTypeClone(_8), chiselTypeClone(_9), chiselTypeClone(_10)
+ )
}
}
diff --git a/core/src/main/scala/chisel3/experimental/verification/package.scala b/core/src/main/scala/chisel3/experimental/verification/package.scala
deleted file mode 100644
index 190083fd..00000000
--- a/core/src/main/scala/chisel3/experimental/verification/package.scala
+++ /dev/null
@@ -1,60 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-
-package chisel3.experimental
-
-import chisel3._
-import chisel3.internal.Builder
-import chisel3.internal.firrtl.{Formal, Verification}
-import chisel3.internal.sourceinfo.SourceInfo
-
-package object verification {
-
- object assert {
- /** Named class for assertions. */
- final class Assert(private[chisel3] val predicate: Bool) extends BaseSim
-
-
- def apply(predicate: Bool, msg: String = "")(
- implicit sourceInfo: SourceInfo,
- compileOptions: CompileOptions): Assert = {
- val a = new Assert(predicate)
- when (!Module.reset.asBool) {
- val clock = Module.clock
- Builder.pushCommand(Verification(a, Formal.Assert, sourceInfo, clock.ref, predicate.ref, msg))
- }
- a
- }
- }
-
- object assume {
- /** Named class for assumes. */
- final class Assume(private[chisel3] val predicate: Bool) extends BaseSim
-
- def apply(predicate: Bool, msg: String = "")(
- implicit sourceInfo: SourceInfo,
- compileOptions: CompileOptions): Assume = {
- val a = new Assume(predicate)
- when (!Module.reset.asBool) {
- val clock = Module.clock
- Builder.pushCommand(Verification(a, Formal.Assume, sourceInfo, clock.ref, predicate.ref, msg))
- }
- a
- }
- }
-
- object cover {
- /** Named class for covers. */
- final class Cover(private[chisel3] val predicate: Bool) extends BaseSim
-
- def apply(predicate: Bool, msg: String = "")(
- implicit sourceInfo: SourceInfo,
- compileOptions: CompileOptions): Cover = {
- val clock = Module.clock
- val c = new Cover(predicate)
- when (!Module.reset.asBool) {
- Builder.pushCommand(Verification(c, Formal.Cover, sourceInfo, clock.ref, predicate.ref, msg))
- }
- c
- }
- }
-}
diff --git a/core/src/main/scala/chisel3/internal/Builder.scala b/core/src/main/scala/chisel3/internal/Builder.scala
index 441abc92..71894887 100644
--- a/core/src/main/scala/chisel3/internal/Builder.scala
+++ b/core/src/main/scala/chisel3/internal/Builder.scala
@@ -6,7 +6,7 @@ import scala.util.DynamicVariable
import scala.collection.mutable.ArrayBuffer
import chisel3._
import chisel3.experimental._
-import chisel3.experimental.hierarchy.Instance
+import chisel3.experimental.hierarchy.{Instance, Clone}
import chisel3.internal.firrtl._
import chisel3.internal.naming._
import _root_.firrtl.annotations.{CircuitName, ComponentName, IsMember, ModuleName, Named, ReferenceTarget}
@@ -105,7 +105,7 @@ private[chisel3] trait HasId extends InstanceId {
private var auto_seed: Option[String] = None
// Prefix at time when this class is constructed
- private val construction_prefix: Prefix = Builder.getPrefix()
+ private val construction_prefix: Prefix = Builder.getPrefix
// Prefix when the latest [[suggestSeed]] or [[autoSeed]] is called
private var prefix_seed: Prefix = Nil
@@ -133,7 +133,7 @@ private[chisel3] trait HasId extends InstanceId {
private[chisel3] def forceAutoSeed(seed: String): this.type = {
auto_seed = Some(seed)
for(hook <- auto_postseed_hooks) { hook(seed) }
- prefix_seed = Builder.getPrefix()
+ prefix_seed = Builder.getPrefix
this
}
@@ -149,17 +149,28 @@ private[chisel3] trait HasId extends InstanceId {
*/
def suggestName(seed: =>String): this.type = {
if(suggested_seed.isEmpty) suggested_seed = Some(seed)
- prefix_seed = Builder.getPrefix()
+ prefix_seed = Builder.getPrefix
for(hook <- suggest_postseed_hooks) { hook(seed) }
this
}
+ // Internal version of .suggestName that can override a user-suggested name
+ // This only exists for maintaining "val io" naming in compatibility-mode Modules without IO
+ // wrapping
+ private[chisel3] def forceFinalName(seed: String): this.type = {
+ // This could be called with user prefixes, ignore them
+ noPrefix {
+ suggested_seed = Some(seed)
+ this.suggestName(seed)
+ }
+ }
+
/** Computes the name of this HasId, if one exists
* @param defaultPrefix Optionally provide a default prefix for computing the name
* @param defaultSeed Optionally provide default seed for computing the name
* @return the name, if it can be computed
*/
- def computeName(defaultPrefix: Option[String], defaultSeed: Option[String]): Option[String] = {
+ private[chisel3] def _computeName(defaultPrefix: Option[String], defaultSeed: Option[String]): Option[String] = {
/** Computes a name of this signal, given the seed and prefix
* @param seed
* @param prefix
@@ -203,7 +214,7 @@ private[chisel3] trait HasId extends InstanceId {
// (e.g. tried to suggest a name to part of a Record)
private[chisel3] def forceName(prefix: Option[String], default: =>String, namespace: Namespace): Unit =
if(_ref.isEmpty) {
- val candidate_name = computeName(prefix, Some(default)).get
+ val candidate_name = _computeName(prefix, Some(default)).get
val available_name = namespace.name(candidate_name)
setRef(Ref(available_name))
}
@@ -223,7 +234,7 @@ private[chisel3] trait HasId extends InstanceId {
private def refName(c: Component): String = _ref match {
case Some(arg) => arg fullName c
- case None => computeName(None, None).get
+ case None => _computeName(None, None).get
}
// Helper for reifying views if they map to a single Target
@@ -332,9 +343,6 @@ private[chisel3] trait NamedComponent extends HasId {
private[chisel3] class ChiselContext() {
val idGen = new IdGen
- // Record the Bundle instance, class name, method name, and reverse stack trace position of open Bundles
- val bundleStack: ArrayBuffer[(Bundle, String, String, Int)] = ArrayBuffer()
-
// Records the different prefixes which have been scoped at this point in time
var prefixStack: Prefix = Nil
@@ -349,8 +357,6 @@ private[chisel3] class DynamicContext(val annotationSeq: AnnotationSeq) {
val components = ArrayBuffer[Component]()
val annotations = ArrayBuffer[ChiselAnnotation]()
var currentModule: Option[BaseModule] = None
- // This is only used for testing, it can be removed if the plugin becomes mandatory
- var allowReflectiveAutoCloneType = true
/** Contains a mapping from a elaborated module to their aspect
* Set by [[ModuleAspect]]
@@ -485,7 +491,7 @@ private[chisel3] object Builder extends LazyLogging {
}
// Returns the prefix stack at this moment
- def getPrefix(): Prefix = chiselContext.get().prefixStack
+ def getPrefix: Prefix = chiselContext.get().prefixStack
def currentModule: Option[BaseModule] = dynamicContextVar.value match {
case Some(dyanmicContext) => dynamicContext.currentModule
@@ -550,6 +556,8 @@ private[chisel3] object Builder extends LazyLogging {
// A bare api call is, e.g. calling Wire() from the scala console).
)
}
+ def hasDynamicContext: Boolean = dynamicContextVar.value.isDefined
+
def readyForModuleConstr: Boolean = dynamicContext.readyForModuleConstr
def readyForModuleConstr_=(target: Boolean): Unit = {
dynamicContext.readyForModuleConstr = target
@@ -572,7 +580,7 @@ private[chisel3] object Builder extends LazyLogging {
dynamicContext.whenStack = s
}
- def currentWhen(): Option[WhenContext] = dynamicContext.whenStack.headOption
+ def currentWhen: Option[WhenContext] = dynamicContext.whenStack.headOption
def currentClock: Option[Clock] = dynamicContext.currentClock
def currentClock_=(newClock: Option[Clock]): Unit = {
@@ -590,16 +598,6 @@ private[chisel3] object Builder extends LazyLogging {
.getOrElse(false)
}
- // This should only be used for testing, must be true outside of Builder context
- def allowReflectiveAutoCloneType: Boolean = {
- dynamicContextVar.value
- .map(_.allowReflectiveAutoCloneType)
- .getOrElse(true)
- }
- def allowReflectiveAutoCloneType_=(value: Boolean): Unit = {
- dynamicContext.allowReflectiveAutoCloneType = value
- }
-
def forcedClock: Clock = currentClock.getOrElse(
throwException("Error: No implicit clock.")
)
@@ -615,52 +613,18 @@ private[chisel3] object Builder extends LazyLogging {
}
def pushOp[T <: Data](cmd: DefPrim[T]): T = {
// Bind each element of the returned Data to being a Op
- cmd.id.bind(OpBinding(forcedUserModule, currentWhen()))
+ cmd.id.bind(OpBinding(forcedUserModule, currentWhen))
pushCommand(cmd).id
}
- // Called when Bundle construction begins, used to record a stack of open Bundle constructors to
- // record candidates for Bundle autoclonetype. This is a best-effort guess.
- // Returns the current stack of open Bundles
- // Note: elt will NOT have finished construction, its elements cannot be accessed
- def updateBundleStack(elt: Bundle): Seq[Bundle] = {
- val stackElts = Thread.currentThread().getStackTrace()
- .reverse // so stack frame numbers are deterministic across calls
- .dropRight(2) // discard Thread.getStackTrace and updateBundleStack
-
- // Determine where we are in the Bundle stack
- val eltClassName = elt.getClass.getName
- val eltStackPos = stackElts.map(_.getClassName).lastIndexOf(eltClassName)
-
- // Prune the existing Bundle stack of closed Bundles
- // If we know where we are in the stack, discard frames above that
- val stackEltsTop = if (eltStackPos >= 0) eltStackPos else stackElts.size
- val pruneLength = chiselContext.get.bundleStack.reverse.prefixLength { case (_, cname, mname, pos) =>
- pos >= stackEltsTop || stackElts(pos).getClassName != cname || stackElts(pos).getMethodName != mname
- }
- chiselContext.get.bundleStack.trimEnd(pruneLength)
-
- // Return the stack state before adding the most recent bundle
- val lastStack = chiselContext.get.bundleStack.map(_._1).toSeq
-
- // Append the current Bundle to the stack, if it's on the stack trace
- if (eltStackPos >= 0) {
- val stackElt = stackElts(eltStackPos)
- chiselContext.get.bundleStack.append((elt, eltClassName, stackElt.getMethodName, eltStackPos))
- }
- // Otherwise discard the stack frame, this shouldn't fail noisily
-
- lastStack
- }
-
/** Recursively suggests names to supported "container" classes
* Arbitrary nestings of supported classes are allowed so long as the
* innermost element is of type HasId
* (Note: Map is Iterable[Tuple2[_,_]] and thus excluded)
*/
def nameRecursively(prefix: String, nameMe: Any, namer: (HasId, String) => Unit): Unit = nameMe match {
- case (id: Instance[_]) => id.cloned match {
- case Right(m: internal.BaseModule.ModuleClone[_]) => namer(m.getPorts, prefix)
+ case (id: Instance[_]) => id.underlying match {
+ case Clone(m: internal.BaseModule.ModuleClone[_]) => namer(m.getPorts, prefix)
case _ =>
}
case (id: HasId) => namer(id, prefix)
@@ -727,14 +691,16 @@ private[chisel3] object Builder extends LazyLogging {
renames
}
- private [chisel3] def build[T <: BaseModule](f: => T, dynamicContext: DynamicContext): (Circuit, T) = {
+ private[chisel3] def build[T <: BaseModule](f: => T, dynamicContext: DynamicContext, forceModName: Boolean = true): (Circuit, T) = {
dynamicContextVar.withValue(Some(dynamicContext)) {
ViewParent // Must initialize the singleton in a Builder context or weird things can happen
// in tiny designs/testcases that never access anything in chisel3.internal
checkScalaVersion()
logger.info("Elaborating design...")
val mod = f
- mod.forceName(None, mod.name, globalNamespace)
+ if (forceModName) { // This avoids definition name index skipping with D/I
+ mod.forceName(None, mod.name, globalNamespace)
+ }
errors.checkpoint(logger)
logger.info("Done elaborating.")
diff --git a/core/src/main/scala/chisel3/internal/MonoConnect.scala b/core/src/main/scala/chisel3/internal/MonoConnect.scala
index 5cbab329..6173fc91 100644
--- a/core/src/main/scala/chisel3/internal/MonoConnect.scala
+++ b/core/src/main/scala/chisel3/internal/MonoConnect.scala
@@ -36,33 +36,35 @@ import chisel3.internal.sourceinfo.SourceInfo
*/
private[chisel3] object MonoConnect {
+ def formatName(data: Data) = s"""${data.earlyName} in ${data.parentNameOpt.getOrElse("(unknown)")}"""
+
// These are all the possible exceptions that can be thrown.
// These are from element-level connection
- def UnreadableSourceException =
- MonoConnectException(": Source is unreadable from current module.")
- def UnwritableSinkException =
- MonoConnectException(": Sink is unwriteable by current module.")
- def SourceEscapedWhenScopeException =
- MonoConnectException(": Source has escaped the scope of the when in which it was constructed.")
- def SinkEscapedWhenScopeException =
- MonoConnectException(": Sink has escaped the scope of the when in which it was constructed.")
+ def UnreadableSourceException(sink: Data, source: Data) =
+ MonoConnectException(s"""${formatName(source)} cannot be read from module ${sink.parentNameOpt.getOrElse("(unknown)")}.""")
+ def UnwritableSinkException(sink: Data, source: Data) =
+ MonoConnectException(s"""${formatName(sink)} cannot be written from module ${source.parentNameOpt.getOrElse("(unknown)")}.""")
+ def SourceEscapedWhenScopeException(source: Data) =
+ MonoConnectException(s"Source ${formatName(source)} has escaped the scope of the when in which it was constructed.")
+ def SinkEscapedWhenScopeException(sink: Data) =
+ MonoConnectException(s"Sink ${formatName(sink)} has escaped the scope of the when in which it was constructed.")
def UnknownRelationException =
- MonoConnectException(": Sink or source unavailable to current module.")
+ MonoConnectException("Sink or source unavailable to current module.")
// These are when recursing down aggregate types
def MismatchedVecException =
- MonoConnectException(": Sink and Source are different length Vecs.")
+ MonoConnectException("Sink and Source are different length Vecs.")
def MissingFieldException(field: String) =
- MonoConnectException(s": Source Record missing field ($field).")
- def MismatchedException(sink: String, source: String) =
- MonoConnectException(s": Sink ($sink) and Source ($source) have different types.")
+ MonoConnectException(s"Source Record missing field ($field).")
+ def MismatchedException(sink: Data, source: Data) =
+ MonoConnectException(s"Sink (${sink.cloneType.toString}) and Source (${source.cloneType.toString}) have different types.")
def DontCareCantBeSink =
- MonoConnectException(": DontCare cannot be a connection sink (LHS)")
- def AnalogCantBeMonoSink =
- MonoConnectException(": Analog cannot participate in a mono connection (sink - LHS)")
- def AnalogCantBeMonoSource =
- MonoConnectException(": Analog cannot participate in a mono connection (source - RHS)")
- def AnalogMonoConnectionException =
- MonoConnectException(": Analog cannot participate in a mono connection (source and sink)")
+ MonoConnectException("DontCare cannot be a connection sink")
+ def AnalogCantBeMonoSink(sink: Data) =
+ MonoConnectException(s"Sink ${formatName(sink)} of type Analog cannot participate in a mono connection (:=)")
+ def AnalogCantBeMonoSource(source: Data) =
+ MonoConnectException(s"Source ${formatName(source)} of type Analog cannot participate in a mono connection (:=)")
+ def AnalogMonoConnectionException(source: Data, sink: Data) =
+ MonoConnectException(s"Source ${formatName(source)} and sink ${formatName(sink)} of type Analog cannot participate in a mono connection (:=)")
def checkWhenVisibility(x: Data): Boolean = {
x.topBinding match {
@@ -169,13 +171,13 @@ private[chisel3] object MonoConnect {
// DontCare as a sink is illegal.
case (DontCare, _) => throw DontCareCantBeSink
// Analog is illegal in mono connections.
- case (_: Analog, _:Analog) => throw AnalogMonoConnectionException
+ case (_: Analog, _:Analog) => throw AnalogMonoConnectionException(source, sink)
// Analog is illegal in mono connections.
- case (_: Analog, _) => throw AnalogCantBeMonoSink
+ case (_: Analog, _) => throw AnalogCantBeMonoSink(sink)
// Analog is illegal in mono connections.
- case (_, _: Analog) => throw AnalogCantBeMonoSource
+ case (_, _: Analog) => throw AnalogCantBeMonoSource(source)
// Sink and source are different subtypes of data so fail
- case (sink, source) => throw MismatchedException(sink.toString, source.toString)
+ case (sink, source) => throw MismatchedException(sink, source)
}
// This function (finally) issues the connection operation
@@ -196,7 +198,7 @@ private[chisel3] object MonoConnect {
val source = reify(_source)
// If source has no location, assume in context module
// This can occur if is a literal, unbound will error previously
- val sink_mod: BaseModule = sink.topBinding.location.getOrElse(throw UnwritableSinkException)
+ val sink_mod: BaseModule = sink.topBinding.location.getOrElse(throw UnwritableSinkException(sink, source))
val source_mod: BaseModule = source.topBinding.location.getOrElse(context_mod)
val sink_parent = Builder.retrieveParent(sink_mod, context_mod).getOrElse(None)
@@ -206,11 +208,11 @@ private[chisel3] object MonoConnect {
val source_direction = BindingDirection.from(source.topBinding, source.direction)
if (!checkWhenVisibility(sink)) {
- throw SinkEscapedWhenScopeException
+ throw SinkEscapedWhenScopeException(sink)
}
if (!checkWhenVisibility(source)) {
- throw SourceEscapedWhenScopeException
+ throw SourceEscapedWhenScopeException(source)
}
// CASE: Context is same module that both left node and right node are in
@@ -220,7 +222,7 @@ private[chisel3] object MonoConnect {
// CURRENT MOD CURRENT MOD
case (Output, _) => issueConnect(sink, source)
case (Internal, _) => issueConnect(sink, source)
- case (Input, _) => throw UnwritableSinkException
+ case (Input, _) => throw UnwritableSinkException(sink, source)
}
}
@@ -238,11 +240,11 @@ private[chisel3] object MonoConnect {
if (!(connectCompileOptions.dontAssumeDirectionality)) {
issueConnect(sink, source)
} else {
- throw UnreadableSourceException
+ throw UnreadableSourceException(sink, source)
}
}
case (Input, Output) if (!(connectCompileOptions.dontTryConnectionsSwapped)) => issueConnect(source, sink)
- case (Input, _) => throw UnwritableSinkException
+ case (Input, _) => throw UnwritableSinkException(sink, source)
}
}
@@ -253,8 +255,8 @@ private[chisel3] object MonoConnect {
// SINK SOURCE
// CHILD MOD CURRENT MOD
case (Input, _) => issueConnect(sink, source)
- case (Output, _) => throw UnwritableSinkException
- case (Internal, _) => throw UnwritableSinkException
+ case (Output, _) => throw UnwritableSinkException(sink, source)
+ case (Internal, _) => throw UnwritableSinkException(sink, source)
}
}
@@ -268,15 +270,15 @@ private[chisel3] object MonoConnect {
// CHILD MOD CHILD MOD
case (Input, Input) => issueConnect(sink, source)
case (Input, Output) => issueConnect(sink, source)
- case (Output, _) => throw UnwritableSinkException
+ case (Output, _) => throw UnwritableSinkException(sink, source)
case (_, Internal) => {
if (!(connectCompileOptions.dontAssumeDirectionality)) {
issueConnect(sink, source)
} else {
- throw UnreadableSourceException
+ throw UnreadableSourceException(sink, source)
}
}
- case (Internal, _) => throw UnwritableSinkException
+ case (Internal, _) => throw UnwritableSinkException(sink, source)
}
}
diff --git a/core/src/main/scala/chisel3/internal/firrtl/Converter.scala b/core/src/main/scala/chisel3/internal/firrtl/Converter.scala
index f56c3b15..ac784882 100644
--- a/core/src/main/scala/chisel3/internal/firrtl/Converter.scala
+++ b/core/src/main/scala/chisel3/internal/firrtl/Converter.scala
@@ -7,10 +7,11 @@ import chisel3.internal.sourceinfo.{NoSourceInfo, SourceInfo, SourceLine, Unloca
import firrtl.{ir => fir}
import chisel3.internal.{HasId, castToInt, throwException}
-import scala.annotation.tailrec
+import scala.annotation.{nowarn, tailrec}
import scala.collection.immutable.Queue
import scala.collection.immutable.LazyList // Needed for 2.12 alias
+@nowarn("msg=class Port") // delete when Port becomes private
private[chisel3] object Converter {
// TODO modeled on unpack method on Printable, refactor?
def unpack(pable: Printable, ctx: Component): (String, Seq[Arg]) = pable match {
@@ -142,8 +143,8 @@ private[chisel3] object Converter {
Some(fir.IsInvalid(convert(info), convert(arg, ctx, info)))
case e @ DefInstance(info, id, _) =>
Some(fir.DefInstance(convert(info), e.name, id.name))
- case Stop(info, clock, ret) =>
- Some(fir.Stop(convert(info), ret, convert(clock, ctx, info), firrtl.Utils.one))
+ case e @ Stop(_, info, clock, ret) =>
+ Some(fir.Stop(convert(info), ret, convert(clock, ctx, info), firrtl.Utils.one, e.name))
case e @ Printf(_, info, clock, pable) =>
val (fmt, args) = unpack(pable, ctx)
Some(fir.Print(convert(info), fir.StringLit(fmt),
diff --git a/core/src/main/scala/chisel3/internal/firrtl/IR.scala b/core/src/main/scala/chisel3/internal/firrtl/IR.scala
index 0b568548..68f5f18e 100644
--- a/core/src/main/scala/chisel3/internal/firrtl/IR.scala
+++ b/core/src/main/scala/chisel3/internal/firrtl/IR.scala
@@ -13,6 +13,7 @@ import _root_.firrtl.annotations.Annotation
import scala.collection.immutable.NumericRange
import scala.math.BigDecimal.RoundingMode
+import scala.annotation.nowarn
case class PrimOp(name: String) {
@@ -64,7 +65,7 @@ object PrimOp {
val AsAsyncResetOp = PrimOp("asAsyncReset")
}
-abstract class Arg {
+sealed abstract class Arg {
def localName: String = name
def contextualName(ctx: Component): String = name
def fullName(ctx: Component): String = contextualName(ctx)
@@ -86,6 +87,19 @@ case class Node(id: HasId) extends Arg {
}
}
+object Arg {
+ def earlyLocalName(id: HasId): String = id.getOptionRef match {
+ case Some(Index(Node(imm), Node(value))) => s"${earlyLocalName(imm)}[${earlyLocalName(imm)}]"
+ case Some(Index(Node(imm), arg)) => s"${earlyLocalName(imm)}[${arg.localName}]"
+ case Some(Slot(Node(imm), name)) => s"${earlyLocalName(imm)}.$name"
+ case Some(arg) => arg.name
+ case None => id match {
+ case data: Data => data._computeName(None, Some("?")).get
+ case _ => "?"
+ }
+ }
+}
+
abstract class LitArg(val num: BigInt, widthArg: Width) extends Arg {
private[chisel3] def forcedWidth = widthArg.known
private[chisel3] def width: Width = if (forcedWidth) widthArg else Width(minWidth)
@@ -196,6 +210,7 @@ case class Slot(imm: Node, name: String) extends Arg {
if (immName.isEmpty) name else s"$immName.$name"
}
}
+
case class Index(imm: Arg, value: Arg) extends Arg {
def name: String = s"[$value]"
override def contextualName(ctx: Component): String = s"${imm.contextualName(ctx)}[${value.contextualName(ctx)}]"
@@ -775,6 +790,7 @@ case class DefRegInit(sourceInfo: SourceInfo, id: Data, clock: Arg, reset: Arg,
case class DefMemory(sourceInfo: SourceInfo, id: HasId, t: Data, size: BigInt) extends Definition
case class DefSeqMemory(sourceInfo: SourceInfo, id: HasId, t: Data, size: BigInt, readUnderWrite: fir.ReadUnderWrite.Value) extends Definition
case class DefMemPort[T <: Data](sourceInfo: SourceInfo, id: T, source: Node, dir: MemPortDirection, index: Arg, clock: Arg) extends Definition
+@nowarn("msg=class Port") // delete when Port becomes private
case class DefInstance(sourceInfo: SourceInfo, id: BaseModule, ports: Seq[Port]) extends Definition
case class WhenBegin(sourceInfo: SourceInfo, pred: Arg) extends Command
case class WhenEnd(sourceInfo: SourceInfo, firrtlDepth: Int, hasAlt: Boolean = false) extends Command
@@ -784,7 +800,9 @@ case class Connect(sourceInfo: SourceInfo, loc: Node, exp: Arg) extends Command
case class BulkConnect(sourceInfo: SourceInfo, loc1: Node, loc2: Node) extends Command
case class Attach(sourceInfo: SourceInfo, locs: Seq[Node]) extends Command
case class ConnectInit(sourceInfo: SourceInfo, loc: Node, exp: Arg) extends Command
-case class Stop(sourceInfo: SourceInfo, clock: Arg, ret: Int) extends Command
+case class Stop(id: stop.Stop, sourceInfo: SourceInfo, clock: Arg, ret: Int) extends Definition
+// Note this is just deprecated which will cause deprecation warnings, use @nowarn
+@deprecated("This API should never have been public, for Module port reflection, use DataMirror.modulePorts", "Chisel 3.5")
case class Port(id: Data, dir: SpecifiedDirection)
case class Printf(id: printf.Printf, sourceInfo: SourceInfo, clock: Arg, pable: Printable) extends Definition
object Formal extends Enumeration {
@@ -792,14 +810,17 @@ object Formal extends Enumeration {
val Assume = Value("assume")
val Cover = Value("cover")
}
-case class Verification[T <: BaseSim](id: T, op: Formal.Value, sourceInfo: SourceInfo, clock: Arg,
+case class Verification[T <: VerificationStatement](id: T, op: Formal.Value, sourceInfo: SourceInfo, clock: Arg,
predicate: Arg, message: String) extends Definition
+@nowarn("msg=class Port") // delete when Port becomes private
abstract class Component extends Arg {
def id: BaseModule
def name: String
def ports: Seq[Port]
}
+@nowarn("msg=class Port") // delete when Port becomes private
case class DefModule(id: RawModule, name: String, ports: Seq[Port], commands: Seq[Command]) extends Component
+@nowarn("msg=class Port") // delete when Port becomes private
case class DefBlackBox(id: BaseBlackBox, name: String, ports: Seq[Port], topDir: SpecifiedDirection, params: Map[String, Param]) extends Component
case class Circuit(name: String, components: Seq[Component], annotations: Seq[ChiselAnnotation], renames: RenameMap) {
diff --git a/core/src/main/scala/chisel3/internal/plugin/package.scala b/core/src/main/scala/chisel3/internal/plugin/package.scala
index c17baf22..9b9b41cd 100644
--- a/core/src/main/scala/chisel3/internal/plugin/package.scala
+++ b/core/src/main/scala/chisel3/internal/plugin/package.scala
@@ -3,27 +3,8 @@
package chisel3.internal
package object plugin {
- /** Used by Chisel's compiler plugin to automatically name signals
- * DO NOT USE in your normal Chisel code!!!
- *
- * @param name The name to use
- * @param nameMe The thing to be named
- * @tparam T The type of the thing to be named
- * @return The thing, but now named
- * @note This is the version called by chisel3-plugin prior to v3.4.1
- */
- def autoNameRecursively[T <: Any](name: String, nameMe: T): T = {
- chisel3.internal.Builder.nameRecursively(
- name.replace(" ", ""),
- nameMe,
- (id: chisel3.internal.HasId, n: String) => id.autoSeed(n)
- )
- nameMe
- }
// The actual implementation
- // Cannot be unified with (String, T) => T (v3.4.0 version) because of special behavior of ports
- // in .autoSeed
private def _autoNameRecursively[T <: Any](prevId: Long, name: String, nameMe: T): T = {
chisel3.internal.Builder.nameRecursively(
name,
diff --git a/core/src/main/scala/chisel3/internal/prefix.scala b/core/src/main/scala/chisel3/internal/prefix.scala
index 9dc14901..620d0864 100644
--- a/core/src/main/scala/chisel3/internal/prefix.scala
+++ b/core/src/main/scala/chisel3/internal/prefix.scala
@@ -51,7 +51,7 @@ private[chisel3] object prefix { // scalastyle:ignore
// This causes extra prefixes to be added, and subsequently cleared in the
// Module constructor. Thus, we need to just make sure if the previous push
// was an incorrect one, to not pop off an empty stack
- if(Builder.getPrefix().nonEmpty) Builder.popPrefix()
+ if(Builder.getPrefix.nonEmpty) Builder.popPrefix()
ret
}
}
@@ -77,7 +77,7 @@ private[chisel3] object noPrefix {
* @return The return value of the provided function
*/
def apply[T](f: => T): T = {
- val prefix = Builder.getPrefix()
+ val prefix = Builder.getPrefix
Builder.clearPrefix()
val ret = f
Builder.setPrefix(prefix)
diff --git a/core/src/main/scala/chisel3/package.scala b/core/src/main/scala/chisel3/package.scala
index 64cfa8b9..faca3ae4 100644
--- a/core/src/main/scala/chisel3/package.scala
+++ b/core/src/main/scala/chisel3/package.scala
@@ -50,10 +50,18 @@ package object chisel3 {
/** Int to UInt conversion, recommended style for variables.
*/
- def asUInt(): UInt = UInt.Lit(bigint, Width())
+ def asUInt: UInt = UInt.Lit(bigint, Width())
+
+ @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5")
+ def asUInt(dummy: Int*): UInt = asUInt
+
/** Int to SInt conversion, recommended style for variables.
*/
- def asSInt(): SInt = SInt.Lit(bigint, Width())
+ def asSInt: SInt = SInt.Lit(bigint, Width())
+
+ @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5")
+ def asSInt(dummy: Int*): SInt = asSInt
+
/** Int to UInt conversion with specified width, recommended style for variables.
*/
def asUInt(width: Width): UInt = UInt.Lit(bigint, width)
@@ -68,17 +76,21 @@ package object chisel3 {
implicit class fromStringToLiteral(str: String) {
/** String to UInt parse, recommended style for constants.
*/
- def U: UInt = str.asUInt()
+ def U: UInt = str.asUInt
/** String to UInt parse with specified width, recommended style for constants.
*/
def U(width: Width): UInt = str.asUInt(width)
/** String to UInt parse, recommended style for variables.
*/
- def asUInt(): UInt = {
+ def asUInt: UInt = {
val bigInt = parse(str)
UInt.Lit(bigInt, Width(bigInt.bitLength max 1))
}
+
+ @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5")
+ def asUInt(dummy: Int*): UInt = asUInt
+
/** String to UInt parse with specified width, recommended style for variables.
*/
def asUInt(width: Width): UInt = UInt.Lit(parse(str), width)
@@ -107,7 +119,10 @@ package object chisel3 {
/** Boolean to Bool conversion, recommended style for variables.
*/
- def asBool(): Bool = Bool.Lit(boolean)
+ def asBool: Bool = Bool.Lit(boolean)
+
+ @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5")
+ def asBool(dummy: Int*): Bool = asBool
}
// Fixed Point is experimental for now, but we alias the implicit conversion classes here
@@ -206,6 +221,7 @@ package object chisel3 {
def getDataElements(a: Aggregate): Seq[Element] = {
a.allElements
}
+ @deprecated("duplicated with DataMirror.fullModulePorts, this returns an internal API, will be removed in Chisel 3.6", "Chisel 3.5")
def getModulePorts(m: Module): Seq[Port] = m.getPorts
class BindingException(message: String) extends ChiselException(message)
diff --git a/docs/README.md b/docs/README.md
index 2a34fc45..23755bc9 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -24,6 +24,14 @@ Our documentation strategy for this repository is as follows:
* Tutorials are kept in a separate repository.
This documentation is hosted on the Chisel [website](https://www.chisel-lang.org).
+Currently, edits to this repo which are backported to the most recent stable branch
+(`3.4.x` at time of writing) will be picked up automatically by the
+website [repository](https://github.com/freechipsproject/www.chisel-lang.org) and pushed live within
+a day or so.
+If you create a *new* document page, you probably also want to:
+ 1. Make sure to add it to the "Contents" page of the corresponding directory [cookbooks](src/cookbooks/cookbooks.md),
+ [explanations](src/explanations/explanations.md), etc.
+ 1. Update the sidebar on the website [here](https://github.com/freechipsproject/www.chisel-lang.org/blob/master/docs/src/main/resources/microsite/data/menu.yml).
## mdoc
diff --git a/docs/src/appendix/appendix.md b/docs/src/appendix/appendix.md
index 0efedbfe..55244cdb 100644
--- a/docs/src/appendix/appendix.md
+++ b/docs/src/appendix/appendix.md
@@ -11,4 +11,5 @@ This section covers some less-common Chisel topics.
* [Differences between Chisel3 and Chisel2](chisel3-vs-chisel2)
* [Experimental Features](experimental-features)
* [Upgrading from Scala 2.11](upgrading-from-scala-2-11)
+* [Upgrading from Chisel 3.4](upgrading-from-chisel-3-4)
* [Versioning](versioning)
diff --git a/docs/src/appendix/experimental-features.md b/docs/src/appendix/experimental-features.md
index 4b1208aa..92226f8f 100644
--- a/docs/src/appendix/experimental-features.md
+++ b/docs/src/appendix/experimental-features.md
@@ -3,6 +3,7 @@ layout: docs
title: "Experimental Features"
section: "chisel3"
---
+# Experimental Features
Chisel has a number of new features that are worth checking out. This page is an informal list of these features and projects.
@@ -12,6 +13,7 @@ Chisel has a number of new features that are worth checking out. This page is a
- [Interval Type](#interval-type)
- [Loading Memories for simulation or FPGA initialization](#loading-memories)
+
### FixedPoint <a name="fixed-point"></a>
FixedPoint numbers are basic *Data* type along side of UInt, SInt, etc. Most common math and logic operations
are supported. Chisel allows both the width and binary point to be inferred by the Firrtl compiler which can simplify
diff --git a/docs/src/appendix/upgrading-from-chisel-3-4.md b/docs/src/appendix/upgrading-from-chisel-3-4.md
new file mode 100644
index 00000000..f7b02820
--- /dev/null
+++ b/docs/src/appendix/upgrading-from-chisel-3-4.md
@@ -0,0 +1,145 @@
+---
+layout: docs
+title: "Upgrading From Chisel 3.4 to 3.5"
+section: "chisel3"
+---
+
+<!-- Prelude -->
+```scala mdoc:invisible
+import chisel3._
+```
+<!-- End Prelude -->
+
+## Upgrading From Chisel 3.4 to 3.5
+
+Chisel 3.5 was a major step forward. It added support for Scala 2.13 as well as dropped many long deprecated APIs.
+Some users may run into issues while upgrading so this page serves as a central location to describe solutions to common issues.
+
+
+### General Strategy for Upgrade
+
+Users are encouraged to first upgrade to the latest version of Chisel 3.4 (3.4.4 at the time of writing) and resolve all deprecation warnings. Doing so should enable a smoother transition to Chisel 3.5.
+
+### Common Issues
+
+#### Value io is not a member of chisel3.Module
+
+This issue most often arises when there are two implementations of a given `Module` that may be chosen between by a generator parameter.
+For example:
+
+```scala mdoc
+class Foo extends Module {
+ val io = IO(new Bundle {
+ val in = Input(UInt(8.W))
+ val out = Output(UInt(8.W))
+ })
+ io.out := io.in
+}
+
+class Bar extends Module {
+ val io = IO(new Bundle {
+ val in = Input(UInt(8.W))
+ val out = Output(UInt(8.W))
+ })
+ io.out := io.in + 1.U
+}
+```
+
+```scala mdoc:fail
+class Example(useBar: Boolean) extends Module {
+ val io = IO(new Bundle {
+ val in = Input(UInt(8.W))
+ val out = Output(UInt(8.W))
+ })
+
+ val inst = if (useBar) {
+ Module(new Bar)
+ } else {
+ Module(new Foo)
+ }
+
+ inst.io.in := io.in
+ io.out := inst.io.out
+}
+```
+
+`Foo` and `Bar` clearly have the same interface, yet we get a type error in Chisel 3.5.
+Notably, while this does work in Chisel 3.4, it does throw a deprecation warning.
+In short, this code is relying on old behavior of the Scala type inferencer.
+In Scala 2.11 and before, the type inferred for `val inst` is: `Module { def io : { def in : UInt; def out : UInt } }`.
+And in fact, if we manually ascribe this type to `val inst`, our same code from above works in Chisel 3.5:
+
+```scala mdoc
+class Example(useBar: Boolean) extends Module {
+ val io = IO(new Bundle {
+ val in = Input(UInt(8.W))
+ val out = Output(UInt(8.W))
+ })
+
+ val inst: Module { def io : { def in : UInt; def out : UInt } } = if (useBar) {
+ Module(new Bar)
+ } else {
+ Module(new Foo)
+ }
+
+ inst.io.in := io.in
+ io.out := inst.io.out
+}
+```
+
+So what is going on and why is this type so ugly?
+This is called a [_structural_ (or _duck_) type](https://en.wikipedia.org/wiki/Structural_type_system).
+Basically, code does not provide any unifying type for `Foo` and `Bar` so the compiler does its best to make one up.
+One negative consequence of the old Scala behavior is that structural type inference makes it very easy to accidentally
+change the public API of your code without meaning to.
+Thus, in the bump from Scala 2.11 to 2.12, the behavior of the Scala compiler changed to not do structural type inference by default.
+
+The solution, is to explicitly provide a type to the Scala compiler:
+
+```scala mdoc:invisible:reset
+import chisel3._
+```
+
+```scala mdoc
+trait HasCommonInterface extends Module {
+ val io = IO(new Bundle {
+ val in = Input(UInt(8.W))
+ val out = Output(UInt(8.W))
+ })
+}
+
+class Foo extends Module with HasCommonInterface {
+ io.out := io.in
+}
+
+class Bar extends Module with HasCommonInterface {
+ io.out := io.in + 1.U
+}
+```
+
+Now our original code works:
+
+```scala mdoc
+class Example(useBar: Boolean) extends Module {
+ val io = IO(new Bundle {
+ val in = IO(Input(UInt(8.W)))
+ val out = IO(Output(UInt(8.W)))
+ })
+
+ // Now, inst is inferred to be of type "HasCommonInterface"
+ val inst = if (useBar) {
+ Module(new Bar)
+ } else {
+ Module(new Foo)
+ }
+
+ inst.io.in := io.in
+ io.out := inst.io.out
+}
+```
+
+**Historical Note**
+
+This may sound similar because a very similar error is included in [Common Issues](upgrading-from-scala-2-11#common-issues) in the Appendix for upgrading from Scala 2.11 to 2.12.
+The workaround employed in Chisel for Scala 2.12 did not work in Scala 2.13, so we came up with the more robust solution described above.
+
diff --git a/docs/src/appendix/upgrading-from-scala-2-11.md b/docs/src/appendix/upgrading-from-scala-2-11.md
index 26e2d252..6724e3e1 100644
--- a/docs/src/appendix/upgrading-from-scala-2-11.md
+++ b/docs/src/appendix/upgrading-from-scala-2-11.md
@@ -14,6 +14,8 @@ import chisel3._
## Upgrading From Scala 2.11 to 2.12
+**As of Chisel 3.5, support for Scala 2.11 has been dropped. This page is only relevant to Chisel versions 3.4 and earlier**
+
As the latest (and probably last) release of Scala 2.11 (2.11.12) was released on 2 November 2017, the time has come to deprecate support for Scala 2.11.
Chisel 3.4 is the last version of Chisel that will support Scala 2.11, so users should upgrade to Scala 2.12
This document is intended to help guide Chisel users through this process; both the "Why?" and the "How?".
diff --git a/docs/src/appendix/versioning.md b/docs/src/appendix/versioning.md
index 8c5ef91c..9f799275 100644
--- a/docs/src/appendix/versioning.md
+++ b/docs/src/appendix/versioning.md
@@ -17,19 +17,23 @@ Historically, due to a mistake in versioning with chisel-iotesters as well as so
the compatible versions of Chisel-related projects has not been obvious.
We are taking steps to improve the situation by bringing the major versions more in line (the `B` part in `A.B.C`),
but the inconsistencies remain in previously published versions.
+Beginning with Chisel 3.5, the major versions for all projects are aligned on `A.5`).
Please use the following table to determine which versions of the related projects are compatible.
In particular, versions of projects in this table were compiled against the version of any dependencies listed in the same row.
For example, `chisel-iotesters` version 1.4 was compiled against `chisel3` version 3.3.
-| chisel3 | chiseltest | chisel-iotesters | firrtl | treadle | diagrammer | firrtl-interpreter<sup>2</sup> |
-| ------- | ---------- | ---------------- | ------ | ------- | ---------- | ----- |
-| 3.4 | 0.3 | 1.5 | 1.4 | 1.3 | 1.3 | 1.4 |
-| 3.3 | 0.2 | 1.4 | 1.3 | 1.2 | 1.2 | 1.3 |
-| 3.2 | 0.1<sup>1</sup> | 1.3 | 1.2 | 1.1 | 1.1 | 1.2 |
-| 3.1 | - | 1.2 | 1.1 | 1.0 | 1.0 | 1.1 |
-| 3.0 | - | 1.1 | 1.0 | -<sup>3</sup> | - | 1.0 |
+| chisel3 | chiseltest | chisel-iotesters<sup>3</sup> | firrtl | treadle | diagrammer | firrtl-interpreter<sup>2</sup> |
+| ------- | ---------- | ---------------- | ------ | ------- | ---------- | ----- |
+| 3.5 | 0.5<sup>4</sup> | 2.5<sup>5</sup> | 1.5 | 1.5<sup>4</sup> | 1.5<sup>4</sup> | - |
+| 3.4 | 0.3 | 1.5 | 1.4 | 1.3 | 1.3 | 1.4 |
+| 3.3 | 0.2 | 1.4 | 1.3 | 1.2 | 1.2 | 1.3 |
+| 3.2 | 0.1<sup>1</sup> | 1.3 | 1.2 | 1.1 | 1.1 | 1.2 |
+| 3.1 | - | 1.2 | 1.1 | 1.0 | 1.0 | 1.1 |
+| 3.0 | - | 1.1 | 1.0 | - | - | 1.0 |
<sup>1</sup> chiseltest 0.1 was published under artifact name [chisel-testers2](https://search.maven.org/search?q=a:chisel-testers2_2.12) (0.2 was published under both artifact names)
-<sup>2</sup> Replaced by Treadle, in maintenance mode only since version 1.1
-<sup>3</sup> Treadle was preceded by the firrtl-interpreter
+<sup>2</sup> Replaced by Treadle, in maintenance mode only since version 1.1, final version is 1.4
+<sup>3</sup> Replaced by chiseltest, final version is 2.5
+<sup>4</sup> chiseltest, treadle, and diagrammer skipped X.4 to have a consistent major version with Chisel
+<sup>5</sup> chisel-iotesters skipped from 1.5 to 2.5 to have a consistent major version with Chisel
diff --git a/docs/src/cookbooks/cookbook.md b/docs/src/cookbooks/cookbook.md
index ce49b668..d4cf3030 100644
--- a/docs/src/cookbooks/cookbook.md
+++ b/docs/src/cookbooks/cookbook.md
@@ -24,6 +24,7 @@ Please note that these examples make use of [Chisel's scala-style printing](../e
* [How do I unpack a value ("reverse concatenation") like in Verilog?](#how-do-i-unpack-a-value-reverse-concatenation-like-in-verilog)
* [How do I do subword assignment (assign to some bits in a UInt)?](#how-do-i-do-subword-assignment-assign-to-some-bits-in-a-uint)
* [How do I create an optional I/O?](#how-do-i-create-an-optional-io)
+* [How do I minimize the number of bits used in an output vector](#how-do-i-minimize-the-number-of-bits-used-in-an-output-vector)
* Predictable Naming
* [How do I get Chisel to name signals properly in blocks like when/withClockAndReset?](#how-do-i-get-chisel-to-name-signals-properly-in-blocks-like-whenwithclockandreset)
* [How do I get Chisel to name the results of vector reads properly?](#how-do-i-get-chisel-to-name-the-results-of-vector-reads-properly)
@@ -88,13 +89,14 @@ you are tying off, you can use `chiselTypeOf`:
```scala mdoc:silent:reset
import chisel3._
+import chisel3.stage.ChiselStage
class MyBundle extends Bundle {
val foo = UInt(4.W)
val bar = Vec(4, UInt(1.W))
}
-class Foo(typ: Data) extends RawModule {
+class Foo(typ: MyBundle) extends RawModule {
val bundleA = IO(Output(typ))
val bundleB = IO(Output(typ))
@@ -107,9 +109,7 @@ class Foo(typ: Data) extends RawModule {
bundleB := 0.U.asTypeOf(chiselTypeOf(bundleB))
}
-class Bar extends RawModule {
- val foo = Module(new Foo(new MyBundle()))
-}
+ChiselStage.emitVerilog(new Foo(new MyBundle))
```
### How do I create a Vec of Bools from a UInt?
@@ -405,6 +405,37 @@ class ModuleWithOptionalIO(flag: Boolean) extends Module {
}
```
+### How do I minimize the number of bits used in an output vector?
+
+Use inferred width and a `Seq` instead of a `Vec`:
+
+Consider:
+
+```scala mdoc:silent:reset
+import chisel3._
+
+// Count the number of set bits up to and including each bit position
+class CountBits(width: Int) extends Module {
+ val bits = IO(Input(UInt(width.W)))
+ val countSequence = Seq.tabulate(width)(i => IO(Output(UInt())))
+ val countVector = IO(Output(Vec(width, UInt())))
+ countSequence.zipWithIndex.foreach { case (port, i) =>
+ port := util.PopCount(bits(i, 0))
+ }
+ countVector := countSequence
+}
+```
+
+Unlike `Vecs` which represent a singular Chisel type and must have the same width for every element,
+`Seq` is a purely Scala construct, so their elements are independent from the perspective of Chisel and can have different widths.
+
+```scala mdoc:verilog
+chisel3.stage.ChiselStage.emitVerilog(new CountBits(4))
+ // remove the body of the module by removing everything after ');'
+ .split("\\);")
+ .head + ");\n"
+```
+
## Predictable Naming
### How do I get Chisel to name signals properly in blocks like when/withClockAndReset?
diff --git a/docs/src/cookbooks/cookbooks.md b/docs/src/cookbooks/cookbooks.md
index ee6f5e45..7c3eb8b9 100644
--- a/docs/src/cookbooks/cookbooks.md
+++ b/docs/src/cookbooks/cookbooks.md
@@ -13,3 +13,5 @@ please [file an issue](https://github.com/chipsalliance/chisel3/issues/new) and
* [General Cookbooks](cookbook)
* [Naming Cookbook](naming)
* [Troubleshooting Guide](troubleshooting)
+* [Hierarchy Cookbook](hierarchy)
+* [DataView Cookbook](dataview)
diff --git a/docs/src/cookbooks/hierarchy.md b/docs/src/cookbooks/hierarchy.md
index 91d99aa6..350d20eb 100644
--- a/docs/src/cookbooks/hierarchy.md
+++ b/docs/src/cookbooks/hierarchy.md
@@ -10,6 +10,8 @@ section: "chisel3"
* [How do I access internal fields of an instance?](#how-do-i-access-internal-fields-of-an-instance)
* [How do I make my parameters accessable from an instance?](#how-do-i-make-my-parameters-accessable-from-an-instance)
* [How do I reuse a previously elaborated module, if my new module has the same parameterization?](#how-do-i-reuse-a-previously-elaborated-module-if-my-new-module-has-the-same-parameterization)
+* [How do I parameterize a module by its children instances?](#how-do-I-parameterize-a-module-by-its-children-instances)
+* [How do I use the new hierarchy-specific Select functions?](#how-do-I-use-the-new-hierarchy-specific-Select-functions)
## How do I instantiate multiple instances with the same module parameterization?
@@ -202,3 +204,58 @@ class AddTwo(addOneDef: Definition[AddOne]) extends Module {
```scala mdoc:verilog
chisel3.stage.ChiselStage.emitVerilog(new AddTwo(Definition(new AddOne(10))))
```
+
+## How do I use the new hierarchy-specific Select functions?
+
+Select functions can be applied after a module has been elaborated, either in a Chisel Aspect or in a parent module applied to a child module.
+
+There are six hierarchy-specific functions, which either return `Instance`'s or `Definition`'s:
+ - `instancesIn(parent)`: Return all instances directly instantiated locally within `parent`
+ - `instancesOf[type](parent)`: Return all instances of provided `type` directly instantiated locally within `parent`
+ - `allInstancesOf[type](root)`: Return all instances of provided `type` directly and indirectly instantiated, locally and deeply, starting from `root`
+ - `definitionsIn`: Return definitions of all instances directly instantiated locally within `parent`
+ - `definitionsOf[type]`: Return definitions of all instances of provided `type` directly instantiated locally within `parent`
+ - `allDefinitionsOf[type]`: Return all definitions of instances of provided `type` directly and indirectly instantiated, locally and deeply, starting from `root`
+
+To demonstrate this, consider the following. We mock up an example where we are using the `Select.allInstancesOf` and `Select.allDefinitionsOf` to annotate instances and the definition of `EmptyModule`. When converting the `ChiselAnnotation` to firrtl's `Annotation`, we print out the resulting `Target`. As shown, despite `EmptyModule` actually only being elaborated once, we still provide different targets depending on how the instance or definition is selected.
+
+```scala mdoc:reset
+import chisel3._
+import chisel3.experimental.hierarchy.{Definition, Instance, Hierarchy, instantiable, public}
+import firrtl.annotations.{IsModule, NoTargetAnnotation}
+case object EmptyAnnotation extends NoTargetAnnotation
+case class MyChiselAnnotation(m: Hierarchy[RawModule], tag: String) extends experimental.ChiselAnnotation {
+ def toFirrtl = {
+ println(tag + ": " + m.toTarget)
+ EmptyAnnotation
+ }
+}
+
+@instantiable
+class EmptyModule extends Module {
+ println("Elaborating EmptyModule!")
+}
+
+@instantiable
+class TwoEmptyModules extends Module {
+ val definition = Definition(new EmptyModule)
+ val i0 = Instance(definition)
+ val i1 = Instance(definition)
+}
+
+class Top extends Module {
+ val definition = Definition(new TwoEmptyModules)
+ val instance = Instance(definition)
+ aop.Select.allInstancesOf[EmptyModule](instance).foreach { i =>
+ experimental.annotate(MyChiselAnnotation(i, "instance"))
+ }
+ aop.Select.allDefinitionsOf[EmptyModule](instance).foreach { d =>
+ experimental.annotate(MyChiselAnnotation(d, "definition"))
+ }
+}
+```
+```scala mdoc:passthrough
+println("```")
+val x = chisel3.stage.ChiselStage.emitFirrtl(new Top)
+println("```")
+```
diff --git a/docs/src/cookbooks/naming.md b/docs/src/cookbooks/naming.md
index a41a1e9a..c7ccdd96 100644
--- a/docs/src/cookbooks/naming.md
+++ b/docs/src/cookbooks/naming.md
@@ -10,7 +10,7 @@ import chisel3.experimental.prefix
import chisel3.experimental.noPrefix
import chisel3.stage.ChiselStage
```
-
+# Naming Cookbook
### I still have _T signals, can this be fixed?
First check - is the compiler plugin properly enabled? Scalac plugins are enabled via the scalac option
diff --git a/docs/src/explanations/blackboxes.md b/docs/src/explanations/blackboxes.md
index 4ecd1ea0..a2a041a7 100644
--- a/docs/src/explanations/blackboxes.md
+++ b/docs/src/explanations/blackboxes.md
@@ -3,6 +3,9 @@ layout: docs
title: "Blackboxes"
section: "chisel3"
---
+
+# BlackBoxes
+
Chisel *BlackBoxes* are used to instantiate externally defined modules. This construct is useful
for hardware constructs that cannot be described in Chisel and for connecting to FPGA or other IP not defined in Chisel.
diff --git a/docs/src/explanations/bundles-and-vecs.md b/docs/src/explanations/bundles-and-vecs.md
index 78626c42..75230c41 100644
--- a/docs/src/explanations/bundles-and-vecs.md
+++ b/docs/src/explanations/bundles-and-vecs.md
@@ -4,6 +4,8 @@ title: "Bundles and Vecs"
section: "chisel3"
---
+# Bundles and Vecs
+
`Bundle` and `Vec` are classes that allow the user to expand the set of Chisel datatypes with aggregates of other types.
Bundles group together several named fields of potentially different types into a coherent unit, much like a `struct` in
@@ -128,48 +130,19 @@ class ModuleProgrammaticMixedVec(x: Int, y: Int) extends Module {
}
```
-### A note on `cloneType`
-
-Since Chisel is built on top of Scala and the JVM, it needs to know how to construct copies of bundles for various
-purposes (creating wires, IOs, etc). If you have a parametrized bundle and Chisel can't automatically figure out how to
-clone your bundle, you will need to create a custom `cloneType` method in your bundle. Most of the time, this is as
-simple as `override def cloneType = (new YourBundleHere(...)).asInstanceOf[this.type]`.
-
-Note that in the vast majority of cases, **this is not required** as Chisel can figure out how to clone most bundles
-automatically.
-
-Here is an example of a parametrized bundle (`ExampleBundle`) that features a custom `cloneType`.
-
-```scala mdoc:silent
-class ExampleBundle(a: Int, b: Int) extends Bundle {
- val foo = UInt(a.W)
- val bar = UInt(b.W)
- override def cloneType = (new ExampleBundle(a, b)).asInstanceOf[this.type]
-}
-
-class ExampleBundleModule(btype: ExampleBundle) extends Module {
- val io = IO(new Bundle {
- val out = Output(UInt(32.W))
- val b = Input(chiselTypeOf(btype))
- })
- io.out := io.b.foo + io.b.bar
-}
+### A note on `cloneType` (For Chisel < 3.5)
-class Top extends Module {
- val io = IO(new Bundle {
- val out = Output(UInt(32.W))
- val in = Input(UInt(17.W))
- })
- val x = Wire(new ExampleBundle(31, 17))
- x := DontCare
- val m = Module(new ExampleBundleModule(x))
- m.io.b.foo := io.in
- m.io.b.bar := io.in
- io.out := m.io.out
-}
-```
+NOTE: This section **only applies to Chisel before Chisel 3.5**.
+As of Chisel 3.5, `Bundle`s should **not** `override def cloneType`,
+as this is a compiler error when using the chisel3 compiler plugin for inferring `cloneType`.
-Generally cloneType can be automatically defined if all arguments to the Bundle are vals e.g.
+Since Chisel is built on top of Scala and the JVM,
+it needs to know how to construct copies of `Bundle`s for various
+purposes (creating wires, IOs, etc).
+If you have a parametrized `Bundle` and Chisel can't automatically figure out how to
+clone it, you will need to create a custom `cloneType` method in your bundle.
+In the vast majority of cases, **this is not required**
+as Chisel can figure out how to clone most `Bundle`s automatically:
```scala mdoc:silent
class MyCloneTypeBundle(val bitwidth: Int) extends Bundle {
@@ -178,13 +151,15 @@ class MyCloneTypeBundle(val bitwidth: Int) extends Bundle {
}
```
-The only caveat is if you are passing something of type Data as a "generator" parameter, in which case you should make
-it a `private val`.
+The only caveat is if you are passing something of type `Data` as a "generator" parameter,
+in which case you should make it a `private val`, and define a `cloneType` method with
+`override def cloneType = (new YourBundleHere(...)).asInstanceOf[this.type]`.
-For example, consider the following Bundle. Because its `gen` variable is not a `private val`, the user has to
-explicitly define the `cloneType` method.
+For example, consider the following `Bundle`. Because its `gen` variable is not a `private val`, the user has to
+explicitly define the `cloneType` method:
-```scala mdoc:silent
+<!-- Cannot compile this because the cloneType is now an error -->
+```scala
import chisel3.util.{Decoupled, Irrevocable}
class RegisterWriteIOExplicitCloneType[T <: Data](gen: T) extends Bundle {
val request = Flipped(Decoupled(gen))
@@ -196,8 +171,10 @@ class RegisterWriteIOExplicitCloneType[T <: Data](gen: T) extends Bundle {
We can make this this infer cloneType by making `gen` private since it is a "type parameter":
```scala mdoc:silent
+import chisel3.util.{Decoupled, Irrevocable}
class RegisterWriteIO[T <: Data](private val gen: T) extends Bundle {
val request = Flipped(Decoupled(gen))
val response = Irrevocable(Bool())
}
```
+
diff --git a/docs/src/explanations/dataview.md b/docs/src/explanations/dataview.md
index 2f229bfc..bb8dbdd1 100644
--- a/docs/src/explanations/dataview.md
+++ b/docs/src/explanations/dataview.md
@@ -10,7 +10,6 @@ _New in Chisel 3.5_
```scala mdoc:invisible
import chisel3._
-import chisel3.stage.ChiselStage.emitVerilog
```
## Introduction
@@ -91,7 +90,7 @@ class MyModule extends RawModule {
Of course, this would result in very different looking Verilog:
```scala mdoc:verilog
-emitVerilog(new MyModule {
+getVerilogString(new MyModule {
override def desiredName = "MyModule"
axi := DontCare // Just to generate Verilog in this stub
})
@@ -147,7 +146,7 @@ class AXIStub extends RawModule {
This will generate Verilog that matches the standard naming convention:
```scala mdoc:verilog
-emitVerilog(new AXIStub)
+getVerilogString(new AXIStub)
```
Note that if both the _Target_ and the _View_ types are subtypes of `Data` (as they are in this example),
@@ -175,7 +174,7 @@ class ConnectionExample extends RawModule {
This results in the corresponding fields being connected in the emitted Verilog:
```scala mdoc:verilog
-emitVerilog(new ConnectionExample)
+getVerilogString(new ConnectionExample)
```
## Other Use Cases
@@ -206,17 +205,6 @@ The issue, is that Chisel primitives like `Mux` and `:=` only operate on subtype
Tuples (as members of the Scala standard library), are not subclasses of `Data`.
`DataView` provides a mechanism to _view_ a `Tuple` as if it were a `Data`:
-<!-- TODO replace this with stdlib import -->
-
-```scala mdoc:invisible
-// ProductDataProduct
-implicit val productDataProduct: DataProduct[Product] = new DataProduct[Product] {
- def dataIterator(a: Product, path: String): Iterator[(Data, String)] = {
- a.productIterator.zipWithIndex.collect { case (d: Data, i) => d -> s"$path._$i" }
- }
-}
-```
-
```scala mdoc
// We need a type to represent the Tuple
class HWTuple2[A <: Data, B <: Data](val _1: A, val _2: B) extends Bundle
@@ -259,16 +247,24 @@ class TupleExample extends RawModule {
```scala mdoc:invisible
// Always emit Verilog to make sure it actually works
-emitVerilog(new TupleExample)
+getVerilogString(new TupleExample)
```
Note that this example ignored `DataProduct` which is another required piece (see [the documentation
about it below](#dataproduct)).
-All of this is slated to be included the Chisel standard library.
+All of this is available to users via a single import:
+```scala mdoc:reset
+import chisel3.experimental.conversions._
+```
## Totality and PartialDataView
+```scala mdoc:reset:invisible
+import chisel3._
+import chisel3.experimental.dataview._
+```
+
A `DataView` is _total_ if all fields of the _Target_ type and all fields of the _View_ type are
included in the mapping.
Chisel will error if a field is accidentally left out from a `DataView`.
@@ -285,7 +281,6 @@ class BundleB extends Bundle {
```
```scala mdoc:crash
-{ // Using an extra scope here to avoid a bug in mdoc (documentation generation)
// We forgot BundleA.foo in the mapping!
implicit val myView = DataView[BundleA, BundleB](_ => new BundleB, _.bar -> _.fizz)
class BadMapping extends Module {
@@ -294,8 +289,7 @@ class BadMapping extends Module {
out := in.viewAs[BundleB]
}
// We must run Chisel to see the error
-emitVerilog(new BadMapping)
-}
+getVerilogString(new BadMapping)
```
As that error suggests, if we *want* the view to be non-total, we can use a `PartialDataView`:
@@ -311,7 +305,7 @@ class PartialDataViewModule extends Module {
```
```scala mdoc:verilog
-emitVerilog(new PartialDataViewModule)
+getVerilogString(new PartialDataViewModule)
```
While `PartialDataViews` need not be total for the _Target_, both `PartialDataViews` and `DataViews`
@@ -321,7 +315,6 @@ This has the consequence that `PartialDataViews` are **not** invertible in the s
For example:
```scala mdoc:crash
-{ // Using an extra scope here to avoid a bug in mdoc (documentation generation)
implicit val myView2 = myView.invert(_ => new BundleA)
class PartialDataViewModule2 extends Module {
val in = IO(Input(new BundleA))
@@ -330,8 +323,7 @@ class PartialDataViewModule2 extends Module {
out.viewAs[BundleA] := in
}
// We must run Chisel to see the error
-emitVerilog(new PartialDataViewModule2)
-}
+getVerilogString(new PartialDataViewModule2)
```
As noted, the mapping must **always** be total for the `View`.
@@ -394,7 +386,7 @@ resolution error.
This section draws heavily from [[1]](https://stackoverflow.com/a/5598107/2483329) and
-[[2]](https://stackoverflow.com/a/5598107/2483329).
+[[2]](https://stackoverflow.com/a/8694558/2483329).
In particular, see [1] for examples.
#### Implicit Resolution Example
@@ -444,7 +436,7 @@ class FooToBar extends Module {
```
```scala mdoc:verilog
-emitVerilog(new FooToBar)
+getVerilogString(new FooToBar)
```
However, it's possible that some user of `Foo` and `Bar` wants different behavior,
@@ -464,7 +456,7 @@ class FooToBarSwizzled extends Module {
```
```scala mdoc:verilog
-emitVerilog(new FooToBarSwizzled)
+getVerilogString(new FooToBarSwizzled)
```
### DataProduct
diff --git a/docs/src/explanations/explanations.md b/docs/src/explanations/explanations.md
index 01894ad7..595bb48c 100644
--- a/docs/src/explanations/explanations.md
+++ b/docs/src/explanations/explanations.md
@@ -16,6 +16,7 @@ read these documents in the following order:
* [Motivation](motivation)
* [Supported Hardware](supported-hardware)
* [Data Types](data-types)
+* [DataView](dataview)
* [Bundles and Vecs](bundles-and-vecs)
* [Combinational Circuits](combinational-circuits)
* [Operators](operators)
diff --git a/docs/src/explanations/functional-abstraction.md b/docs/src/explanations/functional-abstraction.md
index 4e3900b6..596d869a 100644
--- a/docs/src/explanations/functional-abstraction.md
+++ b/docs/src/explanations/functional-abstraction.md
@@ -23,10 +23,10 @@ def clb(a: UInt, b: UInt, c: UInt, d: UInt): UInt =
where ```clb``` is the function which takes ```a```, ```b```,
```c```, ```d``` as arguments and returns a wire to the output of a
boolean circuit. The ```def``` keyword is part of Scala and
-introduces a function definition, with each argument followed by a colon then its type,
-and the function return type given after the colon following the
-argument list. The equals (```=})```sign separates the function argument list from the function
-definition.
+introduces a function definition, with each argument followed by a colon then
+its type, and the function return type given after the colon following the
+argument list. The equals (`=`) sign separates the function argument list
+from the function definition.
We can then use the block in another circuit as follows:
```scala mdoc:silent
diff --git a/docs/src/explanations/modules.md b/docs/src/explanations/modules.md
index f82a14d6..fcdc6020 100644
--- a/docs/src/explanations/modules.md
+++ b/docs/src/explanations/modules.md
@@ -132,7 +132,7 @@ class FooWrapper extends RawModule {
In the example above, the `RawModule` is used to change the reset polarity
of module `SlaveSpi`. Indeed, the reset is active high by default in Chisel
modules, then using `withClockAndReset(clock, !rstn)` we can use an active low
-reset in entire design.
+reset in the entire design.
-The clock is just wired as it, but if needed, `RawModule` can be used in
+The clock is just wired as is, but if needed, `RawModule` can be used in
conjunction with `BlackBox` to connect a differential clock input for example.
diff --git a/docs/src/explanations/multi-clock.md b/docs/src/explanations/multi-clock.md
index 6e9afd5a..eafb5372 100644
--- a/docs/src/explanations/multi-clock.md
+++ b/docs/src/explanations/multi-clock.md
@@ -3,6 +3,8 @@ layout: docs
title: "Multiple Clock Domains"
section: "chisel3"
---
+# Multiple Clock Domains
+
Chisel 3 supports multiple clock domains as follows.
Note that in order to cross clock domains safely, you will need appropriate synchronization logic (such as an asynchronous FIFO). You can use the [AsyncQueue library](https://github.com/ucb-bar/asyncqueue) to do this easily.
diff --git a/docs/src/explanations/naming.md b/docs/src/explanations/naming.md
index 60c653aa..a9f21936 100644
--- a/docs/src/explanations/naming.md
+++ b/docs/src/explanations/naming.md
@@ -3,6 +3,7 @@ layout: docs
title: "Naming"
section: "chisel3"
---
+# Naming
Historically, Chisel has had trouble reliably capturing the names of signals. The reasons for this are due to (1)
primarily relying on reflection to find names, (2) using `@chiselName` macro which had unreliable behavior.
diff --git a/integration-tests/src/test/scala/chiselTests/util/experimental/DecoderSpec.scala b/integration-tests/src/test/scala/chiselTests/util/experimental/DecoderSpec.scala
index c31fdee0..2d50555e 100644
--- a/integration-tests/src/test/scala/chiselTests/util/experimental/DecoderSpec.scala
+++ b/integration-tests/src/test/scala/chiselTests/util/experimental/DecoderSpec.scala
@@ -10,7 +10,7 @@ import chiseltest._
import chiseltest.formal._
class DecoderSpec extends AnyFlatSpec with ChiselScalatestTester with Formal {
- val xor = TruthTable(
+ val xor = TruthTable.fromString(
"""10->1
|01->1
| 0""".stripMargin)
@@ -42,7 +42,7 @@ class DecoderSpec extends AnyFlatSpec with ChiselScalatestTester with Formal {
"""10->1
|01->1
| 0""".stripMargin,
- QMCMinimizer.minimize(TruthTable(
+ QMCMinimizer.minimize(TruthTable.fromString(
"""10->1
|01->1
| 0""".stripMargin)).toString
diff --git a/integration-tests/src/test/scala/chiselTests/util/experimental/minimizer/MinimizerSpec.scala b/integration-tests/src/test/scala/chiselTests/util/experimental/minimizer/MinimizerSpec.scala
index a932eb77..07afd074 100644
--- a/integration-tests/src/test/scala/chiselTests/util/experimental/minimizer/MinimizerSpec.scala
+++ b/integration-tests/src/test/scala/chiselTests/util/experimental/minimizer/MinimizerSpec.scala
@@ -19,7 +19,7 @@ class DecodeTestModule(minimizer: Minimizer, table: TruthTable) extends Module {
chisel3.experimental.verification.assert(
// for each instruction, if input matches, output should match, not no matched, fallback to default
(table.table.map { case (key, value) => (i === key) && (minimizedO === value) } ++
- Seq(table.table.keys.map(i =/= _).reduce(_ && _) && minimizedO === table.default)).reduce(_ || _)
+ Seq(table.table.map(_._1).map(i =/= _).reduce(_ && _) && minimizedO === table.default)).reduce(_ || _)
)
}
diff --git a/macros/src/main/scala/chisel3/internal/InstantiableMacro.scala b/macros/src/main/scala/chisel3/internal/InstantiableMacro.scala
index 1d374198..18c6c7aa 100644
--- a/macros/src/main/scala/chisel3/internal/InstantiableMacro.scala
+++ b/macros/src/main/scala/chisel3/internal/InstantiableMacro.scala
@@ -14,17 +14,24 @@ private[chisel3] object instantiableMacro {
def processBody(stats: Seq[Tree]): (Seq[Tree], Iterable[Tree]) = {
val extensions = scala.collection.mutable.ArrayBuffer.empty[Tree]
extensions += q"implicit val mg = new chisel3.internal.MacroGenerated{}"
+ // Note the triple `_` prefixing `module` is to avoid conflicts if a user marks a 'val module'
+ // with @public; in this case, the lookup code is ambiguous between the generated `def module`
+ // function and the argument to the generated implicit class.
val resultStats = stats.flatMap {
case x @ q"@public val $tpname: $tpe = $name" if tpname.toString() == name.toString() =>
- extensions += atPos(x.pos)(q"def $tpname = module._lookup(_.$tpname)")
+ extensions += atPos(x.pos)(q"def $tpname = ___module._lookup(_.$tpname)")
Nil
case x @ q"@public val $tpname: $tpe = $_" =>
- extensions += atPos(x.pos)(q"def $tpname = module._lookup(_.$tpname)")
+ extensions += atPos(x.pos)(q"def $tpname = ___module._lookup(_.$tpname)")
+ Seq(x)
+ case x @ q"@public val $tpname: $tpe" =>
+ extensions += atPos(x.pos)(q"def $tpname = ___module._lookup(_.$tpname)")
Seq(x)
case x @ q"@public lazy val $tpname: $tpe = $_" =>
- extensions += atPos(x.pos)(q"def $tpname = module._lookup(_.$tpname)")
+ extensions += atPos(x.pos)(q"def $tpname = ___module._lookup(_.$tpname)")
Seq(x)
- case other => Seq(other)
+ case other =>
+ Seq(other)
}
(resultStats, extensions)
}
@@ -38,17 +45,19 @@ private[chisel3] object instantiableMacro {
val defname = TypeName(tpname + c.freshName())
val instname = TypeName(tpname + c.freshName())
val (newStats, extensions) = processBody(stats)
+ val argTParams = tparams.map(_.name)
(q""" $mods class $tpname[..$tparams] $ctorMods(...$paramss) extends { ..$earlydefns } with ..$parents with chisel3.experimental.hierarchy.IsInstantiable { $self => ..$newStats } """,
- Seq(q"""implicit class $defname(module: chisel3.experimental.hierarchy.Definition[$tpname]) { ..$extensions }""",
- q"""implicit class $instname(module: chisel3.experimental.hierarchy.Instance[$tpname]) { ..$extensions } """),
+ Seq(q"""implicit class $defname[..$tparams](___module: chisel3.experimental.hierarchy.Definition[$tpname[..$argTParams]]) { ..$extensions }""",
+ q"""implicit class $instname[..$tparams](___module: chisel3.experimental.hierarchy.Instance[$tpname[..$argTParams]]) { ..$extensions } """),
tpname)
case q"$mods trait $tpname[..$tparams] extends { ..$earlydefns } with ..$parents { $self => ..$stats }" =>
val defname = TypeName(tpname + c.freshName())
val instname = TypeName(tpname + c.freshName())
val (newStats, extensions) = processBody(stats)
+ val argTParams = tparams.map(_.name)
(q"$mods trait $tpname[..$tparams] extends { ..$earlydefns } with ..$parents with chisel3.experimental.hierarchy.IsInstantiable { $self => ..$newStats }",
- Seq(q"""implicit class $defname(module: chisel3.experimental.hierarchy.Definition[$tpname]) { ..$extensions }""",
- q"""implicit class $instname(module: chisel3.experimental.hierarchy.Instance[$tpname]) { ..$extensions } """),
+ Seq(q"""implicit class $defname[..$tparams](___module: chisel3.experimental.hierarchy.Definition[$tpname[..$argTParams]]) { ..$extensions }""",
+ q"""implicit class $instname[..$tparams](___module: chisel3.experimental.hierarchy.Instance[$tpname[..$argTParams]]) { ..$extensions } """),
tpname)
}
val newObj = objOpt match {
diff --git a/macros/src/main/scala/chisel3/internal/sourceinfo/SourceInfoTransform.scala b/macros/src/main/scala/chisel3/internal/sourceinfo/SourceInfoTransform.scala
index a8a7e8d5..ac3e236c 100644
--- a/macros/src/main/scala/chisel3/internal/sourceinfo/SourceInfoTransform.scala
+++ b/macros/src/main/scala/chisel3/internal/sourceinfo/SourceInfoTransform.scala
@@ -165,7 +165,12 @@ object SourceInfoTransform
class SourceInfoTransform(val c: Context) extends AutoSourceTransform {
import c.universe._
- def noArg(): c.Tree = {
+ def noArg: c.Tree = {
+ q"$thisObj.$doFuncTerm($implicitSourceInfo, $implicitCompileOptions)"
+ }
+
+ /** Necessary for dummy methods to auto-apply their arguments to this macro */
+ def noArgDummy(dummy: c.Tree*): c.Tree = {
q"$thisObj.$doFuncTerm($implicitSourceInfo, $implicitCompileOptions)"
}
@@ -224,7 +229,12 @@ object SourceInfoWhiteboxTransform
class SourceInfoWhiteboxTransform(val c: whitebox.Context) extends AutoSourceTransform {
import c.universe._
- def noArg(): c.Tree = {
+ def noArg: c.Tree = {
+ q"$thisObj.$doFuncTerm($implicitSourceInfo, $implicitCompileOptions)"
+ }
+
+ /** Necessary for dummy methods to auto-apply their arguments to this macro */
+ def noArgDummy(dummy: c.Tree*): c.Tree = {
q"$thisObj.$doFuncTerm($implicitSourceInfo, $implicitCompileOptions)"
}
diff --git a/no-plugin-tests/src/test/scala/chisel3/testers/TestUtils.scala b/no-plugin-tests/src/test/scala/chisel3/testers/TestUtils.scala
deleted file mode 120000
index f3ebcbce..00000000
--- a/no-plugin-tests/src/test/scala/chisel3/testers/TestUtils.scala
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../../src/test/scala/chisel3/testers/TestUtils.scala \ No newline at end of file
diff --git a/no-plugin-tests/src/test/scala/chiselTests/AutoClonetypeSpec.scala b/no-plugin-tests/src/test/scala/chiselTests/AutoClonetypeSpec.scala
deleted file mode 120000
index ae3a7597..00000000
--- a/no-plugin-tests/src/test/scala/chiselTests/AutoClonetypeSpec.scala
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../src/test/scala/chiselTests/AutoClonetypeSpec.scala \ No newline at end of file
diff --git a/no-plugin-tests/src/test/scala/chiselTests/AutoNestedCloneSpec.scala b/no-plugin-tests/src/test/scala/chiselTests/AutoNestedCloneSpec.scala
deleted file mode 120000
index 4ff3aa4f..00000000
--- a/no-plugin-tests/src/test/scala/chiselTests/AutoNestedCloneSpec.scala
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../src/test/scala/chiselTests/AutoNestedCloneSpec.scala \ No newline at end of file
diff --git a/no-plugin-tests/src/test/scala/chiselTests/BetterNamingTests.scala b/no-plugin-tests/src/test/scala/chiselTests/BetterNamingTests.scala
deleted file mode 120000
index 0d362f3c..00000000
--- a/no-plugin-tests/src/test/scala/chiselTests/BetterNamingTests.scala
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../src/test/scala/chiselTests/BetterNamingTests.scala \ No newline at end of file
diff --git a/no-plugin-tests/src/test/scala/chiselTests/CatSpec.scala b/no-plugin-tests/src/test/scala/chiselTests/CatSpec.scala
deleted file mode 120000
index 2fb2d6a7..00000000
--- a/no-plugin-tests/src/test/scala/chiselTests/CatSpec.scala
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../src/test/scala/chiselTests/util/CatSpec.scala \ No newline at end of file
diff --git a/no-plugin-tests/src/test/scala/chiselTests/ChiselSpec.scala b/no-plugin-tests/src/test/scala/chiselTests/ChiselSpec.scala
deleted file mode 120000
index 9b257eeb..00000000
--- a/no-plugin-tests/src/test/scala/chiselTests/ChiselSpec.scala
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../src/test/scala/chiselTests/ChiselSpec.scala \ No newline at end of file
diff --git a/no-plugin-tests/src/test/scala/chiselTests/CustomBundle.scala b/no-plugin-tests/src/test/scala/chiselTests/CustomBundle.scala
deleted file mode 120000
index 006a2dbd..00000000
--- a/no-plugin-tests/src/test/scala/chiselTests/CustomBundle.scala
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../src/test/scala/chiselTests/CustomBundle.scala \ No newline at end of file
diff --git a/no-plugin-tests/src/test/scala/chiselTests/InstanceNameSpec.scala b/no-plugin-tests/src/test/scala/chiselTests/InstanceNameSpec.scala
deleted file mode 120000
index e8eca65f..00000000
--- a/no-plugin-tests/src/test/scala/chiselTests/InstanceNameSpec.scala
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../src/test/scala/chiselTests/InstanceNameSpec.scala \ No newline at end of file
diff --git a/no-plugin-tests/src/test/scala/chiselTests/MissingCloneBindingExceptionSpec.scala b/no-plugin-tests/src/test/scala/chiselTests/MissingCloneBindingExceptionSpec.scala
deleted file mode 100644
index 28673495..00000000
--- a/no-plugin-tests/src/test/scala/chiselTests/MissingCloneBindingExceptionSpec.scala
+++ /dev/null
@@ -1,55 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-
-package chiselTests
-import Chisel.ChiselException
-import chisel3.stage.ChiselStage
-import org.scalatest._
-import org.scalatest.matchers.should.Matchers
-
-class MissingCloneBindingExceptionSpec extends ChiselFlatSpec with Matchers with Utils {
- behavior of "missing cloneType in Chisel3"
- ( the [ChiselException] thrownBy extractCause[ChiselException] {
- import chisel3._
-
- class Test extends Module {
- class TestIO(w: Int) extends Bundle {
- val a = Input(Vec(4, UInt(w.W)))
- }
-
- val io = IO(new TestIO(32))
- }
-
- class TestTop extends Module {
- val io = IO(new Bundle {})
-
- val subs = VecInit(Seq.fill(2) {
- Module(new Test).io
- })
- }
-
- ChiselStage.elaborate(new TestTop)
- }).getMessage should include("make all parameters immutable")
-
- behavior of "missing cloneType in Chisel2"
- ( the [ChiselException] thrownBy extractCause[ChiselException] {
- import Chisel._
-
- class Test extends Module {
- class TestIO(w: Int) extends Bundle {
- val a = Vec(4, UInt(width = w)).asInput
- }
-
- val io = IO(new TestIO(32))
- }
-
- class TestTop extends Module {
- val io = IO(new Bundle {})
-
- val subs = Vec.fill(2) {
- Module(new Test).io
- }
- }
-
- ChiselStage.elaborate(new TestTop)
- }).getMessage should include("make all parameters immutable")
-}
diff --git a/no-plugin-tests/src/test/scala/chiselTests/NamingAnnotationTest.scala b/no-plugin-tests/src/test/scala/chiselTests/NamingAnnotationTest.scala
deleted file mode 120000
index 6933a290..00000000
--- a/no-plugin-tests/src/test/scala/chiselTests/NamingAnnotationTest.scala
+++ /dev/null
@@ -1 +0,0 @@
-../../../../../src/test/scala/chiselTests/NamingAnnotationTest.scala \ No newline at end of file
diff --git a/plugin/src/main/scala/chisel3/internal/plugin/BundleComponent.scala b/plugin/src/main/scala/chisel3/internal/plugin/BundleComponent.scala
index 5fe63991..67d744fc 100644
--- a/plugin/src/main/scala/chisel3/internal/plugin/BundleComponent.scala
+++ b/plugin/src/main/scala/chisel3/internal/plugin/BundleComponent.scala
@@ -69,11 +69,14 @@ private[plugin] class BundleComponent(val global: Global, arguments: ChiselPlugi
case con: DefDef if con.symbol.isPrimaryConstructor =>
primaryConstructor = Some(con)
case d: DefDef if isNullaryMethodNamed("_cloneTypeImpl", d) =>
- val msg = "Users cannot override _cloneTypeImpl. Let the compiler plugin generate it. If you must, override cloneType instead."
+ val msg = "Users cannot override _cloneTypeImpl. Let the compiler plugin generate it."
global.globalError(d.pos, msg)
case d: DefDef if isNullaryMethodNamed("_usingPlugin", d) =>
val msg = "Users cannot override _usingPlugin, it is for the compiler plugin's use only."
global.globalError(d.pos, msg)
+ case d: DefDef if isNullaryMethodNamed("cloneType", d) =>
+ val msg = "Users cannot override cloneType. Let the compiler plugin generate it."
+ global.globalError(d.pos, msg)
case _ =>
}
(primaryConstructor, paramAccessors.toList)
diff --git a/project/build.properties b/project/build.properties
index 10fd9eee..baf5ff3e 100644
--- a/project/build.properties
+++ b/project/build.properties
@@ -1 +1 @@
-sbt.version=1.5.5
+sbt.version=1.5.7
diff --git a/project/plugins.sbt b/project/plugins.sbt
index f81a7854..8c19290c 100644
--- a/project/plugins.sbt
+++ b/project/plugins.sbt
@@ -4,25 +4,25 @@ resolvers += Classpaths.sbtPluginReleases
resolvers += "jgit-repo" at "https://download.eclipse.org/jgit/maven"
-addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.9.0")
+addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.9.2")
-addSbtPlugin("com.typesafe.sbt" % "sbt-site" % "1.4.0")
+addSbtPlugin("com.typesafe.sbt" % "sbt-site" % "1.4.1")
addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.10.0")
-addSbtPlugin("com.eed3si9n" % "sbt-unidoc" % "0.4.3")
+addSbtPlugin("com.github.sbt" % "sbt-unidoc" % "0.5.0")
addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.15")
addSbtPlugin("com.thoughtworks.sbt-api-mappings" % "sbt-api-mappings" % "3.0.0")
-addSbtPlugin("org.scalameta" % "sbt-mdoc" % "2.2.23" )
+addSbtPlugin("org.scalameta" % "sbt-mdoc" % "2.2.24" )
addSbtPlugin("com.eed3si9n" % "sbt-sriracha" % "0.1.0")
-addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "1.0.0")
+addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "1.0.1")
-addSbtPlugin("com.geirsson" % "sbt-ci-release" % "1.5.7")
+addSbtPlugin("com.github.sbt" % "sbt-ci-release" % "1.5.10")
// From FIRRTL for building from source
-addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.30")
+addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.33")
diff --git a/src/main/scala/chisel3/ChiselExecutionOptions.scala b/src/main/scala/chisel3/ChiselExecutionOptions.scala
deleted file mode 100644
index 9f635b19..00000000
--- a/src/main/scala/chisel3/ChiselExecutionOptions.scala
+++ /dev/null
@@ -1,49 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-
-package chisel3
-
-import chisel3.stage.{NoRunFirrtlCompilerAnnotation, PrintFullStackTraceAnnotation}
-
-import firrtl.{AnnotationSeq, ExecutionOptionsManager, ComposableOptions}
-
-//TODO: provide support for running firrtl as separate process, could alternatively be controlled by external driver
-//TODO: provide option for not saving chirrtl file, instead calling firrtl with in memory chirrtl
-/**
- * Options that are specific to chisel.
- *
- * @param runFirrtlCompiler when true just run chisel, when false run chisel then compile its output with firrtl
- * @note this extends FirrtlExecutionOptions which extends CommonOptions providing easy access to down chain options
- */
-case class ChiselExecutionOptions(
- runFirrtlCompiler: Boolean = true,
- printFullStackTrace: Boolean = false
- // var runFirrtlAsProcess: Boolean = false
- ) extends ComposableOptions {
-
- def toAnnotations: AnnotationSeq =
- (if (!runFirrtlCompiler) { Seq(NoRunFirrtlCompilerAnnotation) } else { Seq() }) ++
- (if (printFullStackTrace) { Some(PrintFullStackTraceAnnotation) } else { None })
-
-}
-
-trait HasChiselExecutionOptions {
- self: ExecutionOptionsManager =>
-
- var chiselOptions = ChiselExecutionOptions()
-
- parser.note("chisel3 options")
-
- parser.opt[Unit]("no-run-firrtl")
- .abbr("chnrf")
- .foreach { _ =>
- chiselOptions = chiselOptions.copy(runFirrtlCompiler = false)
- }
- .text("Stop after chisel emits chirrtl file")
-
- parser.opt[Unit]("full-stacktrace")
- .foreach { _ =>
- chiselOptions = chiselOptions.copy(printFullStackTrace = true)
- }
- .text("Do not trim stack trace")
-}
-
diff --git a/src/main/scala/chisel3/Driver.scala b/src/main/scala/chisel3/Driver.scala
index fb564446..aa379629 100644
--- a/src/main/scala/chisel3/Driver.scala
+++ b/src/main/scala/chisel3/Driver.scala
@@ -2,85 +2,106 @@
package chisel3
-import chisel3.internal.ErrorLog
import internal.firrtl._
import firrtl._
-import firrtl.options.{Dependency, Phase, PhaseManager, StageError}
-import firrtl.options.phases.DeletedWrapper
-import firrtl.options.Viewer.view
-import firrtl.annotations.JsonProtocol
import firrtl.util.{BackendCompilationUtilities => FirrtlBackendCompilationUtilities}
-import chisel3.stage.{ChiselExecutionResultView, ChiselGeneratorAnnotation, ChiselStage}
-import chisel3.stage.phases.DriverCompatibility
import java.io._
+import _root_.logger.LazyLogging
+@deprecated("Use object firrtl.util.BackendCompilationUtilities instead", "Chisel 3.5")
+trait BackendCompilationUtilities extends LazyLogging {
-/**
- * The Driver provides methods to invoke the chisel3 compiler and the firrtl compiler.
- * By default firrtl is automatically run after chisel. an [[ExecutionOptionsManager]]
- * is needed to manage options. It can parser command line arguments or coordinate
- * multiple chisel toolchain tools options.
- *
- * @example
- * {{{
- * val optionsManager = new ExecutionOptionsManager("chisel3")
- * with HasFirrtlOptions
- * with HasChiselExecutionOptions {
- * commonOptions = CommonOption(targetDirName = "my_target_dir")
- * chiselOptions = ChiselExecutionOptions(runFirrtlCompiler = false)
- * }
- * chisel3.Driver.execute(optionsManager, () => new Dut)
- * }}}
- * or via command line arguments
- * @example {{{
- * args = "--no-run-firrtl --target-dir my-target-dir".split(" +")
- * chisel3.execute(args, () => new DUT)
- * }}}
- */
+ import scala.sys.process.{ProcessBuilder, ProcessLogger, _}
+
+ // Inlined from old trait firrtl.util.BackendCompilationUtilities
+ lazy val TestDirectory = FirrtlBackendCompilationUtilities.TestDirectory
+ def timeStamp: String = FirrtlBackendCompilationUtilities.timeStamp
+ def loggingProcessLogger: ProcessLogger = FirrtlBackendCompilationUtilities.loggingProcessLogger
+ def copyResourceToFile(name: String, file: File): Unit = FirrtlBackendCompilationUtilities.copyResourceToFile(name, file)
+ def createTestDirectory(testName: String): File = FirrtlBackendCompilationUtilities.createTestDirectory(testName)
+ def makeHarness(template: String => String, post: String)(f: File): File =
+ FirrtlBackendCompilationUtilities.makeHarness(template, post)(f)
+ def firrtlToVerilog(prefix: String, dir: File): ProcessBuilder =
+ FirrtlBackendCompilationUtilities.firrtlToVerilog(prefix, dir)
+ def verilogToCpp(
+ dutFile: String,
+ dir: File,
+ vSources: Seq[File],
+ cppHarness: File,
+ suppressVcd: Boolean = false,
+ resourceFileName: String = firrtl.transforms.BlackBoxSourceHelper.defaultFileListName
+ ): ProcessBuilder = {
+ FirrtlBackendCompilationUtilities.verilogToCpp(dutFile, dir, vSources, cppHarness, suppressVcd, resourceFileName)
+ }
+ def cppToExe(prefix: String, dir: File): ProcessBuilder = FirrtlBackendCompilationUtilities.cppToExe(prefix, dir)
+ def executeExpectingFailure(
+ prefix: String,
+ dir: File,
+ assertionMsg: String = ""
+ ): Boolean = {
+ FirrtlBackendCompilationUtilities.executeExpectingFailure(prefix, dir, assertionMsg)
+ }
+ def executeExpectingSuccess(prefix: String, dir: File): Boolean =
+ FirrtlBackendCompilationUtilities.executeExpectingSuccess(prefix, dir)
-trait BackendCompilationUtilities extends FirrtlBackendCompilationUtilities {
/** Compile Chirrtl to Verilog by invoking Firrtl inside the same JVM
*
* @param prefix basename of the file
* @param dir directory where file lives
* @return true if compiler completed successfully
*/
+ @deprecated("Use ChiselStage instead", "Chisel 3.5")
def compileFirrtlToVerilog(prefix: String, dir: File): Boolean = {
- val optionsManager = new ExecutionOptionsManager("chisel3") with HasChiselExecutionOptions with HasFirrtlOptions {
- commonOptions = CommonOptions(topName = prefix, targetDirName = dir.getAbsolutePath)
- firrtlOptions = FirrtlExecutionOptions(compilerName = "verilog")
+
+ // ====== Implemented by inlining logic from ExecutionsOptionManager.toAnnotations =====
+ import firrtl.stage.InfoModeAnnotation
+ import firrtl.stage.phases.DriverCompatibility.TopNameAnnotation
+ import _root_.logger.LogLevelAnnotation
+ val annos: AnnotationSeq = List(
+ InfoModeAnnotation("append"),
+ TopNameAnnotation(prefix),
+ TargetDirAnnotation(dir.getAbsolutePath),
+ LogLevelAnnotation(_root_.logger.LogLevel.None)
+ )
+
+ // ******************* Implemented by inlining firrtl.Driver.execute ***************************
+ import firrtl.stage.phases.DriverCompatibility
+ import firrtl.stage.FirrtlStage
+ import firrtl.options.{Dependency, Phase, PhaseManager}
+ import firrtl.options.phases.DeletedWrapper
+
+ val phases: Seq[Phase] = {
+ import DriverCompatibility._
+ new PhaseManager(
+ List(
+ Dependency[AddImplicitFirrtlFile],
+ Dependency[AddImplicitAnnotationFile],
+ Dependency[AddImplicitOutputFile],
+ Dependency[AddImplicitEmitter],
+ Dependency[FirrtlStage]
+ )
+ ).transformOrder
+ .map(DeletedWrapper(_))
}
- firrtl.Driver.execute(optionsManager) match {
- case _: FirrtlExecutionSuccess => true
- case _: FirrtlExecutionFailure => false
+ val annosx =
+ try {
+ phases.foldLeft(annos)((a, p) => p.transform(a))
+ } catch {
+ case _: firrtl.options.OptionsException => return false
+ }
+ // *********************************************************************************************
+
+ val options = annosx
+
+ // ********** Implemented by inlining firrtl.stage.FirrtlExecutionResultView.view **************
+ import firrtl.stage.FirrtlCircuitAnnotation
+
+ options.collectFirst { case a: FirrtlCircuitAnnotation => a.circuit } match {
+ case None => false
+ case Some(_) => true
}
+ // *********************************************************************************************
}
}
-/**
- * This family provides return values from the chisel3 and possibly firrtl compile steps
- */
-@deprecated("This will be removed in Chisel 3.5", "Chisel3 3.4")
-trait ChiselExecutionResult
-
-/**
- *
- * @param circuitOption Optional circuit, has information like circuit name
- * @param emitted The emitted Chirrrl text
- * @param firrtlResultOption Optional Firrtl result, @see freechipsproject/firrtl for details
- */
-@deprecated("This will be removed in Chisel 3.5", "Chisel 3.4")
-case class ChiselExecutionSuccess(
- circuitOption: Option[Circuit],
- emitted: String,
- firrtlResultOption: Option[FirrtlExecutionResult]
- ) extends ChiselExecutionResult
-
-/**
- * Getting one of these indicates failure of some sort.
- *
- * @param message A clue might be provided here.
- */
-@deprecated("This will be removed in Chisel 3.5", "Chisel 3.4")
-case class ChiselExecutionFailure(message: String) extends ChiselExecutionResult
diff --git a/src/main/scala/chisel3/aop/Select.scala b/src/main/scala/chisel3/aop/Select.scala
index 2384c4d3..8f5a2577 100644
--- a/src/main/scala/chisel3/aop/Select.scala
+++ b/src/main/scala/chisel3/aop/Select.scala
@@ -6,10 +6,12 @@ import chisel3._
import chisel3.internal.{HasId}
import chisel3.experimental.BaseModule
import chisel3.experimental.FixedPoint
-import chisel3.internal.firrtl._
+import chisel3.internal.firrtl.{Definition => DefinitionIR, _}
+import chisel3.experimental.hierarchy._
import chisel3.internal.PseudoModule
import chisel3.internal.BaseModule.ModuleClone
import firrtl.annotations.ReferenceTarget
+import scala.reflect.runtime.universe.TypeTag
import scala.collection.mutable
import chisel3.internal.naming.chiselName
@@ -22,7 +24,6 @@ object Select {
/** Return just leaf components of expanded node
*
* @param d Component to find leafs if aggregate typed. Intermediate fields/indicies are not included
- * @return
*/
def getLeafs(d: Data): Seq[Data] = d match {
case r: Record => r.getElements.flatMap(getLeafs)
@@ -33,7 +34,6 @@ object Select {
/** Return all expanded components, including intermediate aggregate nodes
*
* @param d Component to find leafs if aggregate typed. Intermediate fields/indicies ARE included
- * @return
*/
def getIntermediateAndLeafs(d: Data): Seq[Data] = d match {
case r: Record => r +: r.getElements.flatMap(getIntermediateAndLeafs)
@@ -41,15 +41,156 @@ object Select {
case other => Seq(other)
}
+ /** Selects all instances/modules directly instantiated within given definition
+ *
+ * @param parent
+ */
+ def instancesIn(parent: Hierarchy[BaseModule]): Seq[Instance[BaseModule]] = {
+ check(parent)
+ implicit val mg = new chisel3.internal.MacroGenerated{}
+ parent.proto._component.get match {
+ case d: DefModule => d.commands.collect {
+ case d: DefInstance =>
+ d.id match {
+ case p: chisel3.internal.BaseModule.IsClone[_] =>
+ parent._lookup { x => new Instance(Clone(p)).asInstanceOf[Instance[BaseModule]] }
+ case other: BaseModule =>
+ parent._lookup { x => other }
+ }
+ }
+ case other => Nil
+ }
+ }
+
+ /** Selects all Instances of instances/modules directly instantiated within given module, of provided type
+ *
+ * @note IMPORTANT: this function requires summoning a TypeTag[T], which will fail if T is an inner class.
+ * @param parent hierarchy which instantiates the returned Definitions
+ */
+ def instancesOf[T <: BaseModule : TypeTag](parent: Hierarchy[BaseModule]): Seq[Instance[T]] = {
+ check(parent)
+ implicit val mg = new chisel3.internal.MacroGenerated{}
+ parent.proto._component.get match {
+ case d: DefModule => d.commands.flatMap {
+ case d: DefInstance =>
+ d.id match {
+ case p: chisel3.internal.BaseModule.IsClone[_] =>
+ val i = parent._lookup { x => new Instance(Clone(p)).asInstanceOf[Instance[BaseModule]] }
+ if(i.isA[T]) Some(i.asInstanceOf[Instance[T]]) else None
+ case other: BaseModule =>
+ val i = parent._lookup { x => other }
+ if(i.isA[T]) Some(i.asInstanceOf[Instance[T]]) else None
+ }
+ case other => None
+ }
+ case other => Nil
+ }
+ }
+
+ /** Selects all Instances directly and indirectly instantiated within given root hierarchy, of provided type
+ *
+ * @note IMPORTANT: this function requires summoning a TypeTag[T], which will fail if T is an inner class.
+ * @param root top of the hierarchy to search for instances/modules of given type
+ */
+ def allInstancesOf[T <: BaseModule : TypeTag](root: Hierarchy[BaseModule]): Seq[Instance[T]] = {
+ val soFar = if(root.isA[T]) Seq(root.toInstance.asInstanceOf[Instance[T]]) else Nil
+ val allLocalInstances = instancesIn(root)
+ soFar ++ (allLocalInstances.flatMap(allInstancesOf[T]))
+ }
+
+ /** Selects the Definitions of all instances/modules directly instantiated within given module
+ *
+ * @param parent
+ */
+ def definitionsIn(parent: Hierarchy[BaseModule]): Seq[Definition[BaseModule]] = {
+ type DefType = Definition[BaseModule]
+ implicit val mg = new chisel3.internal.MacroGenerated{}
+ check(parent)
+ val defs = parent.proto._component.get match {
+ case d: DefModule => d.commands.collect {
+ case i: DefInstance =>
+ i.id match {
+ case p: chisel3.internal.BaseModule.IsClone[_] =>
+ parent._lookup { x => new Definition(Proto(p.getProto)).asInstanceOf[Definition[BaseModule]] }
+ case other: BaseModule =>
+ parent._lookup { x => other.toDefinition }
+ }
+ }
+ case other => Nil
+ }
+ val (_, defList) = defs.foldLeft((Set.empty[DefType], List.empty[DefType])) { case ((set, list), definition: Definition[BaseModule]) =>
+ if(set.contains(definition)) (set, list) else (set + definition, definition +: list)
+ }
+ defList.reverse
+ }
+
+
+ /** Selects all Definitions of instances/modules directly instantiated within given module, of provided type
+ *
+ * @note IMPORTANT: this function requires summoning a TypeTag[T], which will fail if T is an inner class.
+ * @param parent hierarchy which instantiates the returned Definitions
+ */
+ def definitionsOf[T <: BaseModule : TypeTag](parent: Hierarchy[BaseModule]): Seq[Definition[T]] = {
+ check(parent)
+ implicit val mg = new chisel3.internal.MacroGenerated{}
+ type DefType = Definition[T]
+ val defs = parent.proto._component.get match {
+ case d: DefModule => d.commands.flatMap {
+ case d: DefInstance =>
+ d.id match {
+ case p: chisel3.internal.BaseModule.IsClone[_] =>
+ val d = parent._lookup { x => new Definition(Clone(p)).asInstanceOf[Definition[BaseModule]] }
+ if(d.isA[T]) Some(d.asInstanceOf[Definition[T]]) else None
+ case other: BaseModule =>
+ val d = parent._lookup { x => other.toDefinition }
+ if(d.isA[T]) Some(d.asInstanceOf[Definition[T]]) else None
+ }
+ case other => None
+ }
+ }
+ val (_, defList) = defs.foldLeft((Set.empty[DefType], List.empty[DefType])) { case ((set, list), definition: Definition[T]) =>
+ if(set.contains(definition)) (set, list) else (set + definition, definition +: list)
+ }
+ defList.reverse
+ }
+
+ /** Selects all Definition's directly and indirectly instantiated within given root hierarchy, of provided type
+ *
+ * @note IMPORTANT: this function requires summoning a TypeTag[T], which will fail if T is an inner class, i.e.
+ * a class defined within another class.
+ * @param root top of the hierarchy to search for definitions of given type
+ */
+ def allDefinitionsOf[T <: BaseModule : TypeTag](root: Hierarchy[BaseModule]): Seq[Definition[T]] = {
+ type DefType = Definition[T]
+ val allDefSet = mutable.HashSet[Definition[BaseModule]]()
+ val defSet = mutable.HashSet[DefType]()
+ val defList = mutable.ArrayBuffer[DefType]()
+ def rec(hier: Definition[BaseModule]): Unit = {
+ if(hier.isA[T] && !defSet.contains(hier.asInstanceOf[DefType])) {
+ defSet += hier.asInstanceOf[DefType]
+ defList += hier.asInstanceOf[DefType]
+ }
+ allDefSet += hier
+ val allDefs = definitionsIn(hier)
+ allDefs.collect {
+ case d if !allDefSet.contains(d) => rec(d)
+ }
+ }
+ rec(root.toDefinition)
+ defList.toList
+ }
+
/** Collects all components selected by collector within module and all children modules it instantiates
* directly or indirectly
* Accepts a collector function, rather than a collector partial function (see [[collectDeep]])
+ *
+ * @note This API will not work with the new experimental hierarchy package. Instead, use allInstancesOf or allDefinitionsOf.
+ *
* @param module Module to collect components, as well as all children module it directly and indirectly instantiates
* @param collector Collector function to pick, given a module, which components to collect
* @param tag Required for generics to work, should ignore this
* @tparam T Type of the component that will be collected
- * @return
*/
def getDeep[T](module: BaseModule)(collector: BaseModule => Seq[T]): Seq[T] = {
check(module)
@@ -63,11 +204,13 @@ object Select {
/** Collects all components selected by collector within module and all children modules it instantiates
* directly or indirectly
* Accepts a collector partial function, rather than a collector function (see [[getDeep]])
+ *
+ * @note This API will not work with the new experimental hierarchy package. Instead, use allInstancesOf or allDefinitionsOf.
+ *
* @param module Module to collect components, as well as all children module it directly and indirectly instantiates
* @param collector Collector partial function to pick, given a module, which components to collect
* @param tag Required for generics to work, should ignore this
* @tparam T Type of the component that will be collected
- * @return
*/
def collectDeep[T](module: BaseModule)(collector: PartialFunction[BaseModule, T]): Iterable[T] = {
check(module)
@@ -78,9 +221,11 @@ object Select {
myItems ++ deepChildrenItems
}
- /** Selects all instances directly instantiated within given module
+ /** Selects all modules directly instantiated within given module
+ *
+ * @note This API will not work with the new experimental hierarchy package. Instead, use instancesIn or definitionsIn.
+ *
* @param module
- * @return
*/
def instances(module: BaseModule): Seq[BaseModule] = {
check(module)
@@ -88,7 +233,7 @@ object Select {
case d: DefModule => d.commands.flatMap {
case i: DefInstance => i.id match {
case m: ModuleClone[_] if !m._madeFromDefinition => None
- case _: PseudoModule => throw new Exception("Aspect APIs are currently incompatible with Definition/Instance")
+ case _: PseudoModule => throw new Exception("instances, collectDeep, and getDeep are currently incompatible with Definition/Instance!")
case other => Some(other)
}
case _ => None
@@ -99,7 +244,6 @@ object Select {
/** Selects all registers directly instantiated within given module
* @param module
- * @return
*/
def registers(module: BaseModule): Seq[Data] = {
check(module)
@@ -111,7 +255,6 @@ object Select {
/** Selects all ios directly contained within given module
* @param module
- * @return
*/
def ios(module: BaseModule): Seq[Data] = {
check(module)
@@ -120,7 +263,6 @@ object Select {
/** Selects all SyncReadMems directly contained within given module
* @param module
- * @return
*/
def syncReadMems(module: BaseModule): Seq[SyncReadMem[_]] = {
check(module)
@@ -131,7 +273,6 @@ object Select {
/** Selects all Mems directly contained within given module
* @param module
- * @return
*/
def mems(module: BaseModule): Seq[Mem[_]] = {
check(module)
@@ -142,7 +283,6 @@ object Select {
/** Selects all arithmetic or logical operators directly instantiated within given module
* @param module
- * @return
*/
def ops(module: BaseModule): Seq[(String, Data)] = {
check(module)
@@ -155,7 +295,6 @@ object Select {
* The kind of operators are contained in [[chisel3.internal.firrtl.PrimOp]]
* @param opKind the kind of operator, e.g. "mux", "add", or "bits"
* @param module
- * @return
*/
def ops(opKind: String)(module: BaseModule): Seq[Data] = {
check(module)
@@ -166,7 +305,6 @@ object Select {
/** Selects all wires in a module
* @param module
- * @return
*/
def wires(module: BaseModule): Seq[Data] = {
check(module)
@@ -177,7 +315,6 @@ object Select {
/** Selects all memory ports, including their direction and memory
* @param module
- * @return
*/
def memPorts(module: BaseModule): Seq[(Data, MemPortDirection, MemBase[_])] = {
check(module)
@@ -189,7 +326,6 @@ object Select {
/** Selects all memory ports of a given direction, including their memory
* @param dir The direction of memory ports to select
* @param module
- * @return
*/
def memPorts(dir: MemPortDirection)(module: BaseModule): Seq[(Data, MemBase[_])] = {
check(module)
@@ -200,7 +336,6 @@ object Select {
/** Selects all components who have been set to be invalid, even if they are later connected to
* @param module
- * @return
*/
def invalids(module: BaseModule): Seq[Data] = {
check(module)
@@ -211,7 +346,6 @@ object Select {
/** Selects all components who are attached to a given signal, within a module
* @param module
- * @return
*/
def attachedTo(module: BaseModule)(signal: Data): Set[Data] = {
check(module)
@@ -226,7 +360,6 @@ object Select {
* E.g. if signal = io.foo.bar, connectionsTo will return all connections to io, io.foo, and io.bar
* @param module
* @param signal
- * @return
*/
def connectionsTo(module: BaseModule)(signal: Data): Seq[PredicatedConnect] = {
check(module)
@@ -237,7 +370,7 @@ object Select {
var seenDef = isPort
searchWhens(module, (cmd: Command, preds) => {
cmd match {
- case cmd: Definition if cmd.id.isInstanceOf[Data] =>
+ case cmd: DefinitionIR if cmd.id.isInstanceOf[Data] =>
val x = getIntermediateAndLeafs(cmd.id.asInstanceOf[Data])
if(x.contains(signal)) prePredicates = preds
case Connect(_, loc@Node(d: Data), exp) =>
@@ -263,13 +396,12 @@ object Select {
/** Selects all stop statements, and includes the predicates surrounding the stop statement
*
* @param module
- * @return
*/
def stops(module: BaseModule): Seq[Stop] = {
val stops = mutable.ArrayBuffer[Stop]()
searchWhens(module, (cmd: Command, preds: Seq[Predicate]) => {
cmd match {
- case chisel3.internal.firrtl.Stop(_, clock, ret) => stops += Stop(preds, ret, getId(clock).asInstanceOf[Clock])
+ case chisel3.internal.firrtl.Stop(_, _, clock, ret) => stops += Stop(preds, ret, getId(clock).asInstanceOf[Clock])
case other =>
}
})
@@ -279,7 +411,6 @@ object Select {
/** Selects all printf statements, and includes the predicates surrounding the printf statement
*
* @param module
- * @return
*/
def printfs(module: BaseModule): Seq[Printf] = {
val printfs = mutable.ArrayBuffer[Printf]()
@@ -297,6 +428,7 @@ object Select {
require(module.isClosed, "Can't use Selector on modules that have not finished construction!")
require(module._component.isDefined, "Can't use Selector on modules that don't have components!")
}
+ private def check(hierarchy: Hierarchy[BaseModule]): Unit = check(hierarchy.proto)
// Given a loc, return all subcomponents of id that could be assigned to in connect
private def getEffected(a: Arg): Seq[Data] = a match {
diff --git a/src/main/scala/chisel3/aop/injecting/InjectingAspect.scala b/src/main/scala/chisel3/aop/injecting/InjectingAspect.scala
index 1a476f61..dc7e6487 100644
--- a/src/main/scala/chisel3/aop/injecting/InjectingAspect.scala
+++ b/src/main/scala/chisel3/aop/injecting/InjectingAspect.scala
@@ -43,7 +43,7 @@ abstract class InjectorAspect[T <: RawModule, M <: RawModule](
injection: M => Unit
) extends Aspect[T] {
final def toAnnotation(top: T): AnnotationSeq = {
- val moduleNames = Select.collectDeep(top) { case i => i.name }.toSeq
+ val moduleNames = Select.allDefinitionsOf[chisel3.experimental.BaseModule](top.toDefinition).map{i => i.toTarget.module }.toSeq
toAnnotation(selectRoots(top), top.name, moduleNames)
}
diff --git a/src/main/scala/chisel3/compatibility.scala b/src/main/scala/chisel3/compatibility.scala
index dde2321d..ccb4ec1f 100644
--- a/src/main/scala/chisel3/compatibility.scala
+++ b/src/main/scala/chisel3/compatibility.scala
@@ -33,7 +33,10 @@ package object Chisel {
implicit class AddDirectionToData[T<:Data](target: T) {
def asInput: T = Input(target)
def asOutput: T = Output(target)
- def flip(): T = Flipped(target)
+ def flip: T = Flipped(target)
+
+ @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5")
+ def flip(dummy: Int*): T = flip
}
implicit class AddDirMethodToData[T<:Data](target: T) {
@@ -362,7 +365,8 @@ package object Chisel {
implicit class fromBooleanToLiteral(x: Boolean) extends chisel3.fromBooleanToLiteral(x)
implicit class fromIntToWidth(x: Int) extends chisel3.fromIntToWidth(x)
- type BackendCompilationUtilities = firrtl.util.BackendCompilationUtilities
+ @deprecated("Use object firrtl.util.BackendCompilationUtilities instead", "Chisel 3.5")
+ type BackendCompilationUtilities = chisel3.BackendCompilationUtilities
val ImplicitConversions = chisel3.util.ImplicitConversions
// Deprecated as of Chisel3
@@ -634,6 +638,7 @@ package object Chisel {
final def toUInt(implicit compileOptions: CompileOptions): UInt = a.do_asUInt(DeprecatedSourceInfo, compileOptions)
+ final def toBools(implicit compileOptions: CompileOptions): Seq[Bool] = a.do_asBools(DeprecatedSourceInfo, compileOptions)
}
}
diff --git a/src/main/scala/chisel3/experimental/conversions/package.scala b/src/main/scala/chisel3/experimental/conversions/package.scala
new file mode 100644
index 00000000..574f9f96
--- /dev/null
+++ b/src/main/scala/chisel3/experimental/conversions/package.scala
@@ -0,0 +1,128 @@
+
+package chisel3.experimental
+
+import chisel3._
+import chisel3.experimental.dataview._
+import scala.language.implicitConversions
+
+/** Implicit conversions from some Scala standard library types and [[Data]]
+ *
+ * @note As this leans heavily on the experimental [[DataView]] feature, these APIs are experimental and subject to change
+ */
+package object conversions {
+
+ /** Implicit conversion between `Seq` and `Vec` */
+ implicit def seq2vec[A : DataProduct, B <: Data](xs: Seq[A])(implicit dv: DataView[A, B]): Vec[B] =
+ xs.viewAs[Vec[B]]
+
+ /** Implicit conversion between [[Tuple2]] and [[HWTuple2]] */
+ implicit def tuple2hwtuple[T1 : DataProduct, T2 : DataProduct, V1 <: Data, V2 <: Data](
+ tup: (T1, T2)
+ )(
+ implicit v1: DataView[T1, V1], v2: DataView[T2, V2]
+ ): HWTuple2[V1, V2] = {
+ tup.viewAs[HWTuple2[V1, V2]]
+ }
+
+ /** Implicit conversion between [[Tuple3]] and [[HWTuple3]] */
+ implicit def tuple3hwtuple[T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, V1 <: Data, V2 <: Data, V3 <: Data](
+ tup: (T1, T2, T3)
+ )(
+ implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3]
+ ): HWTuple3[V1, V2, V3] = {
+ tup.viewAs[HWTuple3[V1, V2, V3]]
+ }
+
+ /** Implicit conversion between [[Tuple4]] and [[HWTuple4]] */
+ implicit def tuple4hwtuple[
+ T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, T4 : DataProduct,
+ V1 <: Data, V2 <: Data, V3 <: Data, V4 <: Data
+ ](
+ tup: (T1, T2, T3, T4)
+ )(
+ implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3], v4: DataView[T4, V4]
+ ): HWTuple4[V1, V2, V3, V4] = {
+ tup.viewAs[HWTuple4[V1, V2, V3, V4]]
+ }
+
+ /** Implicit conversion between [[Tuple5]] and [[HWTuple5]] */
+ implicit def tuple5hwtuple[
+ T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, T4 : DataProduct, T5 : DataProduct,
+ V1 <: Data, V2 <: Data, V3 <: Data, V4 <: Data, V5 <: Data
+ ](
+ tup: (T1, T2, T3, T4, T5)
+ )(
+ implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3], v4: DataView[T4, V4], v5: DataView[T5, V5]
+ ): HWTuple5[V1, V2, V3, V4, V5] = {
+ tup.viewAs[HWTuple5[V1, V2, V3, V4, V5]]
+ }
+
+ /** Implicit conversion between [[Tuple6]] and [[HWTuple6]] */
+ implicit def tuple6hwtuple[
+ T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, T4 : DataProduct, T5 : DataProduct, T6 : DataProduct,
+ V1 <: Data, V2 <: Data, V3 <: Data, V4 <: Data, V5 <: Data, V6 <: Data
+ ](
+ tup: (T1, T2, T3, T4, T5, T6)
+ )(
+ implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3], v4: DataView[T4, V4], v5: DataView[T5, V5],
+ v6: DataView[T6, V6]
+ ): HWTuple6[V1, V2, V3, V4, V5, V6] = {
+ tup.viewAs[HWTuple6[V1, V2, V3, V4, V5, V6]]
+ }
+
+ /** Implicit conversion between [[Tuple7]] and [[HWTuple7]] */
+ implicit def tuple7hwtuple[
+ T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, T4 : DataProduct, T5 : DataProduct,
+ T6 : DataProduct, T7 : DataProduct,
+ V1 <: Data, V2 <: Data, V3 <: Data, V4 <: Data, V5 <: Data, V6 <: Data, V7 <: Data
+ ](
+ tup: (T1, T2, T3, T4, T5, T6, T7)
+ )(
+ implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3], v4: DataView[T4, V4], v5: DataView[T5, V5],
+ v6: DataView[T6, V6], v7: DataView[T7, V7]
+ ): HWTuple7[V1, V2, V3, V4, V5, V6, V7] = {
+ tup.viewAs[HWTuple7[V1, V2, V3, V4, V5, V6, V7]]
+ }
+
+ /** Implicit conversion between [[Tuple8]] and [[HWTuple8]] */
+ implicit def tuple8hwtuple[
+ T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, T4 : DataProduct, T5 : DataProduct,
+ T6 : DataProduct, T7 : DataProduct, T8 : DataProduct,
+ V1 <: Data, V2 <: Data, V3 <: Data, V4 <: Data, V5 <: Data, V6 <: Data, V7 <: Data, V8 <: Data
+ ](
+ tup: (T1, T2, T3, T4, T5, T6, T7, T8)
+ )(
+ implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3], v4: DataView[T4, V4], v5: DataView[T5, V5],
+ v6: DataView[T6, V6], v7: DataView[T7, V7], v8: DataView[T8, V8]
+ ): HWTuple8[V1, V2, V3, V4, V5, V6, V7, V8] = {
+ tup.viewAs[HWTuple8[V1, V2, V3, V4, V5, V6, V7, V8]]
+ }
+
+ /** Implicit conversion between [[Tuple9]] and [[HWTuple9]] */
+ implicit def tuple9hwtuple[
+ T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, T4 : DataProduct, T5 : DataProduct,
+ T6 : DataProduct, T7 : DataProduct, T8 : DataProduct, T9 : DataProduct,
+ V1 <: Data, V2 <: Data, V3 <: Data, V4 <: Data, V5 <: Data, V6 <: Data, V7 <: Data, V8 <: Data, V9 <: Data
+ ](
+ tup: (T1, T2, T3, T4, T5, T6, T7, T8, T9)
+ )(
+ implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3], v4: DataView[T4, V4], v5: DataView[T5, V5],
+ v6: DataView[T6, V6], v7: DataView[T7, V7], v8: DataView[T8, V8], v9: DataView[T9, V9]
+ ): HWTuple9[V1, V2, V3, V4, V5, V6, V7, V8, V9] = {
+ tup.viewAs[HWTuple9[V1, V2, V3, V4, V5, V6, V7, V8, V9]]
+ }
+
+ /** Implicit conversion between [[Tuple10]] and [[HWTuple10]] */
+ implicit def tuple10hwtuple[
+ T1 : DataProduct, T2 : DataProduct, T3 : DataProduct, T4 : DataProduct, T5 : DataProduct,
+ T6 : DataProduct, T7 : DataProduct, T8 : DataProduct, T9 : DataProduct, T10 : DataProduct,
+ V1 <: Data, V2 <: Data, V3 <: Data, V4 <: Data, V5 <: Data, V6 <: Data, V7 <: Data, V8 <: Data, V9 <: Data, V10 <: Data
+ ](
+ tup: (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10)
+ )(
+ implicit v1: DataView[T1, V1], v2: DataView[T2, V2], v3: DataView[T3, V3], v4: DataView[T4, V4], v5: DataView[T5, V5],
+ v6: DataView[T6, V6], v7: DataView[T7, V7], v8: DataView[T8, V8], v9: DataView[T9, V9], v10: DataView[T10, V10]
+ ): HWTuple10[V1, V2, V3, V4, V5, V6, V7, V8, V9, V10] = {
+ tup.viewAs[HWTuple10[V1, V2, V3, V4, V5, V6, V7, V8, V9, V10]]
+ }
+}
diff --git a/src/main/scala/chisel3/experimental/verification/package.scala b/src/main/scala/chisel3/experimental/verification/package.scala
new file mode 100644
index 00000000..a026542d
--- /dev/null
+++ b/src/main/scala/chisel3/experimental/verification/package.scala
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: Apache-2.0
+
+package chisel3.experimental
+
+import chisel3.{Bool, CompileOptions}
+import chisel3.internal.sourceinfo.SourceInfo
+
+package object verification {
+
+ object assert {
+ @deprecated("Please use chisel3.assert instead. The chisel3.experimental.verification package will be removed.", "Chisel 3.5")
+ def apply(predicate: Bool, msg: String = "")
+ (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): chisel3.assert.Assert = chisel3.assert(predicate, msg)
+ }
+
+ object assume {
+ @deprecated("Please use chisel3.assume instead. The chisel3.experimental.verification package will be removed.", "Chisel 3.5")
+ def apply(predicate: Bool, msg: String = "")
+ (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): chisel3.assume.Assume = chisel3.assume(predicate, msg)
+ }
+
+ object cover {
+ @deprecated("Please use chisel3.cover instead. The chisel3.experimental.verification package will be removed.", "Chisel 3.5")
+ def apply(predicate: Bool, msg: String = "")
+ (implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): chisel3.cover.Cover = chisel3.cover(predicate, msg)
+ }
+}
diff --git a/src/main/scala/chisel3/stage/package.scala b/src/main/scala/chisel3/stage/package.scala
index 4d6738d6..c307d3ae 100644
--- a/src/main/scala/chisel3/stage/package.scala
+++ b/src/main/scala/chisel3/stage/package.scala
@@ -24,33 +24,4 @@ package object stage {
}
}
-
- private[chisel3] implicit object ChiselExecutionResultView extends OptionsView[ChiselExecutionResult] {
-
- def view(options: AnnotationSeq): ChiselExecutionResult = {
- var chiselCircuit: Option[ChiselCircuit] = None
- var chirrtlCircuit: Option[String] = None
-
- options.foreach {
- case a @ ChiselCircuitAnnotation(b) =>
- chiselCircuit = Some(b)
- chirrtlCircuit = {
- val anno = CircuitSerializationAnnotation(a.circuit, "", FirrtlFileFormat)
- Some(anno.getBytes.map(_.toChar).mkString)
- }
- case _ =>
- }
-
- val fResult = firrtl.stage.phases.DriverCompatibility.firrtlResultView(options)
-
- (chiselCircuit, chirrtlCircuit) match {
- case (None, _) => ChiselExecutionFailure("Failed to elaborate Chisel circuit")
- case (Some(_), None) => ChiselExecutionFailure("Failed to convert Chisel circuit to FIRRTL")
- case (Some(a), Some(b)) => ChiselExecutionSuccess( Some(a), b, Some(fResult))
- }
-
- }
-
- }
-
}
diff --git a/src/main/scala/chisel3/stage/phases/DriverCompatibility.scala b/src/main/scala/chisel3/stage/phases/DriverCompatibility.scala
index 9305c5c9..847b7179 100644
--- a/src/main/scala/chisel3/stage/phases/DriverCompatibility.scala
+++ b/src/main/scala/chisel3/stage/phases/DriverCompatibility.scala
@@ -2,19 +2,13 @@
package chisel3.stage.phases
-import firrtl.{AnnotationSeq, ExecutionOptionsManager, HasFirrtlOptions}
-import firrtl.annotations.NoTargetAnnotation
-import firrtl.options.{Dependency, OptionsException, OutputAnnotationFileAnnotation, Phase, Unserializable}
-import firrtl.stage.{FirrtlCircuitAnnotation, RunFirrtlTransformAnnotation}
-import firrtl.stage.phases.DriverCompatibility.TopNameAnnotation
+import firrtl.annotations.Annotation
+import firrtl.options.Phase
-import chisel3.HasChiselExecutionOptions
-import chisel3.stage.{ChiselStage, NoRunFirrtlCompilerAnnotation, ChiselOutputFileAnnotation}
-
-/** This provides components of a compatibility wrapper around Chisel's deprecated [[chisel3.Driver]].
+/** This formerly provided components of a compatibility wrapper around Chisel's removed `chisel3.Driver`.
*
- * Primarily, this object includes [[firrtl.options.Phase Phase]]s that generate [[firrtl.annotations.Annotation]]s
- * derived from the deprecated [[firrtl.stage.phases.DriverCompatibility.TopNameAnnotation]].
+ * This object formerly included [[firrtl.options.Phase Phase]]s that generate [[firrtl.annotations.Annotation]]s
+ * derived from the deprecated `firrtl.stage.phases.DriverCompatibility.TopNameAnnotation`.
*/
@deprecated("This object contains no public members. This will be removed in Chisel 3.6.", "Chisel 3.5")
object DriverCompatibility
diff --git a/src/main/scala/chisel3/testers/BasicTester.scala b/src/main/scala/chisel3/testers/BasicTester.scala
index d17407ea..99002660 100644
--- a/src/main/scala/chisel3/testers/BasicTester.scala
+++ b/src/main/scala/chisel3/testers/BasicTester.scala
@@ -21,12 +21,7 @@ class BasicTester extends Module() {
* reset). If your definition of reset is not the encapsulating Module's
* reset, you will need to gate this externally.
*/
- def stop()(implicit sourceInfo: SourceInfo) {
- // TODO: rewrite this using library-style SourceInfo passing.
- when (!reset.asBool) {
- pushCommand(Stop(sourceInfo, clock.ref, 0))
- }
- }
+ def stop()(implicit sourceInfo: SourceInfo): Unit = chisel3.stop()
/** The finish method provides a hook that subclasses of BasicTester can use to
* alter a circuit after their constructor has been called.
diff --git a/src/main/scala/chisel3/util/Arbiter.scala b/src/main/scala/chisel3/util/Arbiter.scala
index 059bdd14..b68acae1 100644
--- a/src/main/scala/chisel3/util/Arbiter.scala
+++ b/src/main/scala/chisel3/util/Arbiter.scala
@@ -10,6 +10,7 @@ import chisel3.internal.naming.chiselName // can't use chisel3_ version because
/** IO bundle definition for an Arbiter, which takes some number of ready-valid inputs and outputs
* (selects) at most one.
+ * @groupdesc Signals The actual hardware fields of the Bundle
*
* @param gen data type
* @param n number of inputs
@@ -17,8 +18,20 @@ import chisel3.internal.naming.chiselName // can't use chisel3_ version because
class ArbiterIO[T <: Data](private val gen: T, val n: Int) extends Bundle {
// See github.com/freechipsproject/chisel3/issues/765 for why gen is a private val and proposed replacement APIs.
+/** Input data, one per potential sender
+ *
+ * @group Signals
+ */
val in = Flipped(Vec(n, Decoupled(gen)))
+/** Output data after arbitration
+ *
+ * @group Signals
+ */
val out = Decoupled(gen)
+/** One-Hot vector indicating which output was chosen
+ *
+ * @group Signals
+ */
val chosen = Output(UInt(log2Ceil(n).W))
}
@@ -47,7 +60,7 @@ abstract class LockingArbiterLike[T <: Data](gen: T, n: Int, count: Int, needsLo
val locked = lockCount.value =/= 0.U
val wantsLock = needsLock.map(_(io.out.bits)).getOrElse(true.B)
- when (io.out.fire() && wantsLock) {
+ when (io.out.fire && wantsLock) {
lockIdx := io.chosen
lockCount.inc()
}
@@ -63,7 +76,7 @@ abstract class LockingArbiterLike[T <: Data](gen: T, n: Int, count: Int, needsLo
class LockingRRArbiter[T <: Data](gen: T, n: Int, count: Int, needsLock: Option[T => Bool] = None)
extends LockingArbiterLike[T](gen, n, count, needsLock) {
- lazy val lastGrant = RegEnable(io.chosen, io.out.fire())
+ lazy val lastGrant = RegEnable(io.chosen, io.out.fire)
lazy val grantMask = (0 until n).map(_.asUInt > lastGrant)
lazy val validMask = io.in zip grantMask map { case (in, g) => in.valid && g }
diff --git a/src/main/scala/chisel3/util/BitPat.scala b/src/main/scala/chisel3/util/BitPat.scala
index 0dcb2466..808245de 100644
--- a/src/main/scala/chisel3/util/BitPat.scala
+++ b/src/main/scala/chisel3/util/BitPat.scala
@@ -4,11 +4,16 @@ package chisel3.util
import scala.language.experimental.macros
import chisel3._
-import chisel3.internal.chiselRuntimeDeprecated
import chisel3.internal.sourceinfo.{SourceInfo, SourceInfoTransform}
object BitPat {
+
+ private[chisel3] implicit val bitPatOrder = new Ordering[BitPat] {
+ import scala.math.Ordered.orderingToOrdered
+ def compare(x: BitPat, y: BitPat): Int = (x.getWidth, x.value, x.mask) compare (y.getWidth, y.value, y.mask)
+ }
+
/** Parses a bit pattern string into (bits, mask, width).
*
* @return bits the literal value, with don't cares being 0
@@ -90,6 +95,7 @@ object BitPat {
* @note the UInt must be a literal
*/
def apply(x: UInt): BitPat = {
+ require(x.isLit, s"$x is not a literal, BitPat.apply(x: UInt) only accepts literals")
val len = if (x.isWidthKnown) x.getWidth else 0
apply("b" + x.litValue.toString(2).reverse.padTo(len, "0").reverse.mkString)
}
@@ -111,6 +117,119 @@ object BitPat {
}
}
+package experimental {
+ object BitSet {
+
+ /** Construct a [[BitSet]] from a sequence of [[BitPat]].
+ * All [[BitPat]] must have the same width.
+ */
+ def apply(bitpats: BitPat*): BitSet = {
+ val bs = new BitSet { def terms = bitpats.flatMap(_.terms).toSet }
+ // check width
+ bs.getWidth
+ bs
+ }
+
+ /** Empty [[BitSet]]. */
+ val empty: BitSet = new BitSet {
+ def terms = Set()
+ }
+
+ /** Construct a [[BitSet]] from String.
+ * each line should be a valid [[BitPat]] string with the same width.
+ */
+ def fromString(str: String): BitSet = {
+ val bs = new BitSet { def terms = str.split('\n').map(str => BitPat(str)).toSet }
+ // check width
+ bs.getWidth
+ bs
+ }
+ }
+
+ /** A Set of [[BitPat]] represents a set of bit vector with mask. */
+ sealed trait BitSet { outer =>
+ /** all [[BitPat]] elements in [[terms]] make up this [[BitSet]].
+ * all [[terms]] should be have the same width.
+ */
+ def terms: Set[BitPat]
+
+ /** Get specified width of said BitSet */
+ def getWidth: Int = {
+ require(terms.map(_.width).size <= 1, s"All BitPats must be the same size! Got $this")
+ // set width = 0 if terms is empty.
+ terms.headOption.map(_.width).getOrElse(0)
+ }
+
+ import BitPat.bitPatOrder
+ override def toString: String = terms.toSeq.sorted.mkString("\n")
+
+ /** whether this [[BitSet]] is empty (i.e. no value matches) */
+ def isEmpty: Boolean = terms.forall(_.isEmpty)
+
+ /** Check whether this [[BitSet]] overlap with that [[BitSet]], i.e. !(intersect.isEmpty)
+ *
+ * @param that [[BitSet]] to be checked.
+ * @return true if this and that [[BitSet]] have overlap.
+ */
+ def overlap(that: BitSet): Boolean =
+ !terms.flatMap(a => that.terms.map(b => (a, b))).forall { case (a, b) => !a.overlap(b) }
+
+ /** Check whether this [[BitSet]] covers that (i.e. forall b matches that, b also matches this)
+ *
+ * @param that [[BitSet]] to be covered
+ * @return true if this [[BitSet]] can cover that [[BitSet]]
+ */
+ def cover(that: BitSet): Boolean =
+ that.subtract(this).isEmpty
+
+ /** Intersect `this` and `that` [[BitSet]].
+ *
+ * @param that [[BitSet]] to be intersected.
+ * @return a [[BitSet]] containing all elements of `this` that also belong to `that`.
+ */
+ def intersect(that: BitSet): BitSet =
+ terms
+ .flatMap(a => that.terms.map(b => a.intersect(b)))
+ .filterNot(_.isEmpty)
+ .fold(BitSet.empty)(_.union(_))
+
+ /** Subtract that from this [[BitSet]].
+ *
+ * @param that subtrahend [[BitSet]].
+ * @return a [[BitSet]] containing elements of `this` which are not the elements of `that`.
+ */
+ def subtract(that: BitSet): BitSet =
+ terms.map { a =>
+ that.terms.map(b => a.subtract(b)).fold(a)(_.intersect(_))
+ }.filterNot(_.isEmpty).fold(BitSet.empty)(_.union(_))
+
+ /** Union this and that [[BitSet]]
+ *
+ * @param that [[BitSet]] to union.
+ * @return a [[BitSet]] containing all elements of `this` and `that`.
+ */
+ def union(that: BitSet): BitSet = new BitSet {
+ def terms = outer.terms ++ that.terms
+ }
+
+ /** Test whether two [[BitSet]] matches the same set of value
+ *
+ * @note
+ * This method can be very expensive compared to ordinary == operator between two Objects
+ *
+ * @return true if two [[BitSet]] is same.
+ */
+ override def equals(obj: Any): Boolean = {
+ obj match {
+ case that: BitSet => this.getWidth == that.getWidth && this.cover(that) && that.cover(this)
+ case _ => false
+ }
+ }
+ }
+
+}
+
+
/** Bit patterns are literals with masks, used to represent values with don't
* care bits. Equality comparisons will ignore don't care bits.
*
@@ -120,19 +239,19 @@ object BitPat {
* "b10001".U === BitPat("b101??") // evaluates to false.B
* }}}
*/
-sealed class BitPat(val value: BigInt, val mask: BigInt, width: Int) extends SourceInfoDoc {
- def getWidth: Int = width
+sealed class BitPat(val value: BigInt, val mask: BigInt, val width: Int) extends util.experimental.BitSet with SourceInfoDoc {
+ import chisel3.util.experimental.BitSet
+ def terms = Set(this)
+
+ /**
+ * Get specified width of said BitPat
+ */
+ override def getWidth: Int = width
def apply(x: Int): BitPat = macro SourceInfoTransform.xArg
def apply(x: Int, y: Int): BitPat = macro SourceInfoTransform.xyArg
def === (that: UInt): Bool = macro SourceInfoTransform.thatArg
def =/= (that: UInt): Bool = macro SourceInfoTransform.thatArg
def ## (that: BitPat): BitPat = macro SourceInfoTransform.thatArg
- override def equals(obj: Any): Boolean = {
- obj match {
- case y: BitPat => value == y.value && mask == y.mask && getWidth == y.getWidth
- case _ => false
- }
- }
/** @group SourceInfoTransformMacro */
def do_apply(x: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): BitPat = {
@@ -161,14 +280,83 @@ sealed class BitPat(val value: BigInt, val mask: BigInt, width: Int) extends Sou
new BitPat((value << that.getWidth) + that.value, (mask << that.getWidth) + that.mask, this.width + that.getWidth)
}
- /** Generate raw string of a BitPat. */
- def rawString: String = Seq.tabulate(width) { i =>
+ /** Check whether this [[BitPat]] overlap with that [[BitPat]], i.e. !(intersect.isEmpty)
+ *
+ * @param that [[BitPat]] to be checked.
+ * @return true if this and that [[BitPat]] have overlap.
+ */
+ def overlap(that: BitPat): Boolean = ((mask & that.mask) & (value ^ that.value)) == 0
+
+ /** Check whether this [[BitSet]] covers that (i.e. forall b matches that, b also matches this)
+ *
+ * @param that [[BitPat]] to be covered
+ * @return true if this [[BitSet]] can cover that [[BitSet]]
+ */
+ def cover(that: BitPat): Boolean = (mask & (~that.mask | (value ^ that.value))) == 0
+
+ /** Intersect `this` and `that` [[BitPat]].
+ *
+ * @param that [[BitPat]] to be intersected.
+ * @return a [[BitSet]] containing all elements of `this` that also belong to `that`.
+ */
+ def intersect(that: BitPat): BitSet = {
+ if (!overlap(that)) {
+ BitSet.empty
+ } else {
+ new BitPat(this.value | that.value, this.mask | that.mask, this.width.max(that.width))
+ }
+ }
+
+ /** Subtract a [[BitPat]] from this.
+ *
+ * @param that subtrahend [[BitPat]].
+ * @return a [[BitSet]] containing elements of `this` which are not the elements of `that`.
+ */
+ def subtract(that: BitPat): BitSet = {
+ require(width == that.width)
+ def enumerateBits(mask: BigInt): Seq[BigInt] = {
+ if (mask == 0) {
+ Nil
+ } else {
+ // bits comes after the first '1' in a number are inverted in its two's complement.
+ // therefore bit is always the first '1' in x (counting from least significant bit).
+ val bit = mask & (-mask)
+ bit +: enumerateBits(mask & ~bit)
+ }
+ }
+
+ val intersection = intersect(that)
+ val omask = this.mask
+ if (intersection.isEmpty) {
+ this
+ } else {
+ new BitSet {
+ val terms =
+ intersection.terms.flatMap { remove =>
+ enumerateBits(~omask & remove.mask).map { bit =>
+ // Only care about higher than current bit in remove
+ val nmask = (omask | ~(bit - 1)) & remove.mask
+ val nvalue = (remove.value ^ bit) & nmask
+ val nwidth = remove.width
+ new BitPat(nvalue, nmask, nwidth)
+ }
+ }
+ }
+ }
+ }
+
+ override def isEmpty: Boolean = false
+
+ /** Generate raw string of a [[BitPat]]. */
+ def rawString: String = Seq
+ .tabulate(width) { i =>
(value.testBit(width - i - 1), mask.testBit(width - i - 1)) match {
- case (true, true) => "1"
- case (false, true) => "0"
- case (_, false) => "?"
+ case (true, true) => "1"
+ case (false, true) => "0"
+ case (_, false) => "?"
+ }
}
- }.mkString
+ .mkString
override def toString = s"BitPat($rawString)"
}
diff --git a/src/main/scala/chisel3/util/Decoupled.scala b/src/main/scala/chisel3/util/Decoupled.scala
index 8909ffe3..4b8b3eeb 100644
--- a/src/main/scala/chisel3/util/Decoupled.scala
+++ b/src/main/scala/chisel3/util/Decoupled.scala
@@ -16,6 +16,7 @@ import chisel3.internal.naming._ // can't use chisel3_ version because of compi
* while the consumer uses the flipped interface (inputs bits).
* The actual semantics of ready/valid are enforced via the use of concrete subclasses.
* @param gen the type of data to be wrapped in Ready/Valid
+ * @groupdesc Signals The actual hardware fields of the Bundle
*/
abstract class ReadyValidIO[+T <: Data](gen: T) extends Bundle
{
@@ -26,8 +27,19 @@ abstract class ReadyValidIO[+T <: Data](gen: T) extends Bundle
case _ => gen
}
+/** Indicates that the consumer is ready to accept the data this cycle
+ * @group Signals
+ */
val ready = Input(Bool())
+
+/** Indicates that the producer has put valid data in 'bits'
+ * @group Signals
+ */
val valid = Output(Bool())
+
+/** The data to be transferred when ready and valid are asserted at the same cycle
+ * @group Signals
+ */
val bits = Output(genType)
}
@@ -37,7 +49,10 @@ object ReadyValidIO {
/** Indicates if IO is both ready and valid
*/
- def fire(): Bool = target.ready && target.valid
+ def fire: Bool = target.ready && target.valid
+
+ @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5")
+ def fire(dummy: Int = 0): Bool = fire
/** Push dat onto the output bits of this interface to let the consumer know it has happened.
* @param dat the values to assign to bits.
@@ -82,9 +97,6 @@ object ReadyValidIO {
* @param gen the type of data to be wrapped in DecoupledIO
*/
class DecoupledIO[+T <: Data](gen: T) extends ReadyValidIO[T](gen)
-{
- override def cloneType: this.type = new DecoupledIO(gen).asInstanceOf[this.type]
-}
/** This factory adds a decoupled handshaking protocol to a data bundle. */
object Decoupled
@@ -121,11 +133,9 @@ object Decoupled
* Additionally, once 'valid' is raised it will never be lowered until after
* 'ready' has also been raised.
* @param gen the type of data to be wrapped in IrrevocableIO
+ * @groupdesc Signals The actual hardware fields of the Bundle
*/
class IrrevocableIO[+T <: Data](gen: T) extends ReadyValidIO[T](gen)
-{
- override def cloneType: this.type = new IrrevocableIO(gen).asInstanceOf[this.type]
-}
/** Factory adds an irrevocable handshaking protocol to a data bundle. */
object Irrevocable
@@ -164,6 +174,7 @@ object DeqIO {
* @param gen The type of data to queue
* @param entries The max number of entries in the queue.
* @param hasFlush A boolean for whether the generated Queue is flushable
+ * @groupdesc Signals The hardware fields of the Bundle
*/
class QueueIO[T <: Data](private val gen: T, val entries: Int, val hasFlush: Boolean = false) extends Bundle
{ // See github.com/freechipsproject/chisel3/issues/765 for why gen is a private val and proposed replacement APIs.
@@ -172,13 +183,21 @@ class QueueIO[T <: Data](private val gen: T, val entries: Int, val hasFlush: Boo
* but internally, the queue implementation itself sits on the other side
* of the interface so uses the flipped instance.
*/
- /** I/O to enqueue data (client is producer, and Queue object is consumer), is [[Chisel.DecoupledIO]] flipped. */
+ /** I/O to enqueue data (client is producer, and Queue object is consumer), is [[Chisel.DecoupledIO]] flipped.
+ * @group Signals
+ */
val enq = Flipped(EnqIO(gen))
- /** I/O to dequeue data (client is consumer and Queue object is producer), is [[Chisel.DecoupledIO]]*/
+ /** I/O to dequeue data (client is consumer and Queue object is producer), is [[Chisel.DecoupledIO]]
+ * @group Signals
+ */
val deq = Flipped(DeqIO(gen))
- /** The current amount of data in the queue */
+ /** The current amount of data in the queue
+ * @group Signals
+ */
val count = Output(UInt(log2Ceil(entries + 1).W))
- /** When asserted, reset the enqueue and dequeue pointers, effectively flushing the queue (Optional IO for a flushable Queue)*/
+ /** When asserted, reset the enqueue and dequeue pointers, effectively flushing the queue (Optional IO for a flushable Queue)
+ * @group Signals
+ */
val flush = if (hasFlush) Some(Input(Bool())) else None
}
@@ -228,9 +247,9 @@ class Queue[T <: Data](val gen: T,
val ptr_match = enq_ptr.value === deq_ptr.value
val empty = ptr_match && !maybe_full
val full = ptr_match && maybe_full
- val do_enq = WireDefault(io.enq.fire())
- val do_deq = WireDefault(io.deq.fire())
- val flush = io.flush.getOrElse(false.B)
+ val do_enq = WireDefault(io.enq.fire)
+ val do_deq = WireDefault(io.deq.fire)
+ val flush = io.flush.getOrElse(false.B)
// when flush is high, empty the queue
// Semantically, any enqueues happen before the flush.
@@ -288,20 +307,26 @@ class Queue[T <: Data](val gen: T,
}
}
-/** Factory for a generic hardware queue.
- *
- * @param enq input (enqueue) interface to the queue, also determines width of queue elements
- * @param entries depth (number of elements) of the queue
- *
- * @return output (dequeue) interface from the queue
- *
- * @example {{{
- * consumer.io.in <> Queue(producer.io.out, 16)
- * }}}
- */
+/** Factory for a generic hardware queue. */
object Queue
{
- /** Create a queue and supply a DecoupledIO containing the product. */
+ /** Create a [[Queue]] and supply a [[DecoupledIO]] containing the product.
+ *
+ * @param enq input (enqueue) interface to the queue, also determines type of queue elements.
+ * @param entries depth (number of elements) of the queue
+ * @param pipe True if a single entry queue can run at full throughput (like a pipeline). The `ready` signals are
+ * combinationally coupled.
+ * @param flow True if the inputs can be consumed on the same cycle (the inputs "flow" through the queue immediately).
+ * The `valid` signals are coupled.
+ * @param useSyncReadMem True uses SyncReadMem instead of Mem as an internal memory element.
+ * @param flush Optional [[Bool]] signal, if defined, the [[Queue.hasFlush]] will be true, and connect correspond
+ * signal to [[Queue]] instance.
+ * @return output (dequeue) interface from the queue.
+ *
+ * @example {{{
+ * consumer.io.in <> Queue(producer.io.out, 16)
+ * }}}
+ */
@chiselName
def apply[T <: Data](
enq: ReadyValidIO[T],
@@ -309,7 +334,7 @@ object Queue
pipe: Boolean = false,
flow: Boolean = false,
useSyncReadMem: Boolean = false,
- hasFlush: Boolean = false): DecoupledIO[T] = {
+ flush: Option[Bool] = None): DecoupledIO[T] = {
if (entries == 0) {
val deq = Wire(new DecoupledIO(chiselTypeOf(enq.bits)))
deq.valid := enq.valid
@@ -317,7 +342,8 @@ object Queue
enq.ready := deq.ready
deq
} else {
- val q = Module(new Queue(chiselTypeOf(enq.bits), entries, pipe, flow, useSyncReadMem, hasFlush))
+ val q = Module(new Queue(chiselTypeOf(enq.bits), entries, pipe, flow, useSyncReadMem, flush.isDefined))
+ q.io.flush.zip(flush).foreach(f => f._1 := f._2)
q.io.enq.valid := enq.valid // not using <> so that override is allowed
q.io.enq.bits := enq.bits
enq.ready := q.io.enq.ready
@@ -325,10 +351,25 @@ object Queue
}
}
- /** Create a queue and supply a IrrevocableIO containing the product.
- * Casting from Decoupled is safe here because we know the Queue has
- * Irrevocable semantics; we didn't want to change the return type of
- * apply() for backwards compatibility reasons.
+ /** Create a queue and supply a [[IrrevocableIO]] containing the product.
+ * Casting from [[DecoupledIO]] is safe here because we know the [[Queue]] has
+ * Irrevocable semantics.
+ * we didn't want to change the return type of apply() for backwards compatibility reasons.
+ *
+ * @param enq [[DecoupledIO]] signal to enqueue.
+ * @param entries The max number of entries in the queue
+ * @param pipe True if a single entry queue can run at full throughput (like a pipeline). The ''ready'' signals are
+ * combinationally coupled.
+ * @param flow True if the inputs can be consumed on the same cycle (the inputs "flow" through the queue immediately).
+ * The ''valid'' signals are coupled.
+ * @param useSyncReadMem True uses SyncReadMem instead of Mem as an internal memory element.
+ * @param flush Optional [[Bool]] signal, if defined, the [[Queue.hasFlush]] will be true, and connect correspond
+ * signal to [[Queue]] instance.
+ * @return a [[DecoupledIO]] signal which should connect to the dequeue signal.
+ *
+ * @example {{{
+ * consumer.io.in <> Queue(producer.io.out, 16)
+ * }}}
*/
@chiselName
def irrevocable[T <: Data](
@@ -336,8 +377,9 @@ object Queue
entries: Int = 2,
pipe: Boolean = false,
flow: Boolean = false,
- useSyncReadMem: Boolean = false): IrrevocableIO[T] = {
- val deq = apply(enq, entries, pipe, flow, useSyncReadMem)
+ useSyncReadMem: Boolean = false,
+ flush: Option[Bool] = None): IrrevocableIO[T] = {
+ val deq = apply(enq, entries, pipe, flow, useSyncReadMem, flush)
require(entries > 0, "Zero-entry queues don't guarantee Irrevocability")
val irr = Wire(new IrrevocableIO(chiselTypeOf(deq.bits)))
irr.bits := deq.bits
diff --git a/src/main/scala/chisel3/util/Enum.scala b/src/main/scala/chisel3/util/Enum.scala
index bf150464..4501a2de 100644
--- a/src/main/scala/chisel3/util/Enum.scala
+++ b/src/main/scala/chisel3/util/Enum.scala
@@ -6,7 +6,6 @@
package chisel3.util
import chisel3._
-import chisel3.internal.chiselRuntimeDeprecated
/** Defines a set of unique UInt constants
*
diff --git a/src/main/scala/chisel3/util/Valid.scala b/src/main/scala/chisel3/util/Valid.scala
index 6c6d685e..5d80502a 100644
--- a/src/main/scala/chisel3/util/Valid.scala
+++ b/src/main/scala/chisel3/util/Valid.scala
@@ -17,20 +17,26 @@ import chisel3._
* @tparam T the type of the data
* @param gen some data
* @see [[Valid$ Valid factory]] for concrete examples
+ * @groupdesc Signals The actual hardware fields of the Bundle
*/
class Valid[+T <: Data](gen: T) extends Bundle {
- /** A bit that will be asserted when `bits` is valid */
+ /** A bit that will be asserted when `bits` is valid
+ * @group Signals
+ */
val valid = Output(Bool())
- /** Some data */
+ /** The data to be transferred, qualified by `valid`
+ * @group Signals
+ */
val bits = Output(gen)
/** True when `valid` is asserted
* @return a Chisel [[Bool]] true if `valid` is asserted
*/
- def fire(dummy: Int = 0): Bool = valid
+ def fire: Bool = valid
- override def cloneType: this.type = Valid(gen).asInstanceOf[this.type]
+ @deprecated("Calling this function with an empty argument list is invalid in Scala 3. Use the form without parentheses instead", "Chisel 3.5")
+ def fire(dummy: Int = 0): Bool = valid
}
/** Factory for generating "valid" interfaces. A "valid" interface is a data-communicating interface between a producer
@@ -172,13 +178,18 @@ class Pipe[T <: Data](val gen: T, val latency: Int = 1)(implicit compileOptions:
/** Interface for [[Pipe]]s composed of a [[Valid]] input and [[Valid]] output
* @define notAQueue
+ * @groupdesc Signals Hardware fields of the Bundle
*/
class PipeIO extends Bundle {
- /** [[Valid]] input */
+ /** [[Valid]] input
+ * @group Signals
+ */
val enq = Input(Valid(gen))
- /** [[Valid]] output. Data will appear here `latency` cycles after being valid at `enq`. */
+ /** [[Valid]] output. Data will appear here `latency` cycles after being valid at `enq`.
+ * @group Signals
+ */
val deq = Output(Valid(gen))
}
diff --git a/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala b/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala
index 1d725875..4dcea99e 100644
--- a/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala
+++ b/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala
@@ -7,11 +7,21 @@ import logger.LazyLogging
case object EspressoNotFoundException extends Exception
+/** A [[Minimizer]] implementation to use espresso to minimize the [[TruthTable]].
+ *
+ * espresso uses heuristic algorithm providing a sub-optimized) result.
+ * For implementation details, please refer to:
+ * [[https://www.springerprofessional.de/en/logic-minimization-algorithms-for-vlsi-synthesis/13780088]]
+ *
+ * a espresso executable should be downloaded from [[https://github.com/chipsalliance/espresso]]
+ *
+ * If user want to user the this [[Minimizer]], a espresso executable should be added to system PATH environment.
+ */
object EspressoMinimizer extends Minimizer with LazyLogging {
def minimize(table: TruthTable): TruthTable =
TruthTable.merge(TruthTable.split(table).map{case (table, indexes) => (espresso(table), indexes)})
- def espresso(table: TruthTable): TruthTable = {
+ private def espresso(table: TruthTable): TruthTable = {
def writeTable(table: TruthTable): String = {
def invert(string: String) = string
.replace('0', 't')
@@ -45,7 +55,7 @@ object EspressoMinimizer extends Minimizer with LazyLogging {
|""".stripMargin ++ (if (defaultType == '1') invertRawTable else rawTable)
}
- def readTable(espressoTable: String): Map[BitPat, BitPat] = {
+ def readTable(espressoTable: String) = {
def bitPat(espresso: String): BitPat = BitPat("b" + espresso.replace('-', '?'))
espressoTable
@@ -53,7 +63,6 @@ object EspressoMinimizer extends Minimizer with LazyLogging {
.filterNot(_.startsWith("."))
.map(_.split(' '))
.map(row => bitPat(row(0)) -> bitPat(row(1)))
- .toMap
}
val input = writeTable(table)
diff --git a/src/main/scala/chisel3/util/experimental/decode/QMCMinimizer.scala b/src/main/scala/chisel3/util/experimental/decode/QMCMinimizer.scala
index c1533f44..59120221 100644
--- a/src/main/scala/chisel3/util/experimental/decode/QMCMinimizer.scala
+++ b/src/main/scala/chisel3/util/experimental/decode/QMCMinimizer.scala
@@ -8,6 +8,15 @@ import scala.annotation.tailrec
import scala.math.Ordered.orderingToOrdered
import scala.language.implicitConversions
+/** A [[Minimizer]] implementation to use Quine-Mccluskey algorithm to minimize the [[TruthTable]].
+ *
+ * This algorithm can always find the best solution, but is a NP-Complete algorithm,
+ * which means, for large-scale [[TruthTable]] minimization task, it will be really slow,
+ * and might run out of memory of JVM stack.
+ *
+ * In this situation, users should consider switch to [[EspressoMinimizer]],
+ * which uses heuristic algorithm providing a sub-optimized result.
+ */
object QMCMinimizer extends Minimizer {
private implicit def toImplicant(x: BitPat): Implicant = new Implicant(x)
@@ -225,11 +234,11 @@ object QMCMinimizer extends Minimizer {
val outputBp = BitPat("b" + "?" * (m - i - 1) + "1" + "?" * i)
// Minterms, implicants that makes the output to be 1
- val mint: Seq[Implicant] = table.table.filter { case (_, t) => t.mask.testBit(i) && t.value.testBit(i) }.keys.map(toImplicant).toSeq
+ val mint: Seq[Implicant] = table.table.filter { case (_, t) => t.mask.testBit(i) && t.value.testBit(i) }.map(_._1).map(toImplicant)
// Maxterms, implicants that makes the output to be 0
- val maxt: Seq[Implicant] = table.table.filter { case (_, t) => t.mask.testBit(i) && !t.value.testBit(i) }.keys.map(toImplicant).toSeq
+ val maxt: Seq[Implicant] = table.table.filter { case (_, t) => t.mask.testBit(i) && !t.value.testBit(i) }.map(_._1).map(toImplicant)
// Don't cares, implicants that can produce either 0 or 1 as output
- val dc: Seq[Implicant] = table.table.filter { case (_, t) => !t.mask.testBit(i) }.keys.map(toImplicant).toSeq
+ val dc: Seq[Implicant] = table.table.filter { case (_, t) => !t.mask.testBit(i) }.map(_._1).map(toImplicant)
val (implicants, defaultToDc) = table.default match {
case x if x.mask.testBit(i) && !x.value.testBit(i) => // default to 0
@@ -282,7 +291,7 @@ object QMCMinimizer extends Minimizer {
(essentialPrimeImplicants ++ getCover(nonessentialPrimeImplicants, uncoveredImplicants)).map(a => (a.bp, outputBp))
})
- minimized.tail.foldLeft(table.copy(table = Map(minimized.head))) { case (tb, t) =>
+ minimized.tail.foldLeft(table.copy(table = Seq(minimized.head))) { case (tb, t) =>
if (tb.table.exists(x => x._1 == t._1)) {
tb.copy(table = tb.table.map { case (k, v) =>
if (k == t._1) {
@@ -291,7 +300,7 @@ object QMCMinimizer extends Minimizer {
} else (k, v)
})
} else {
- tb.copy(table = tb.table + t)
+ tb.copy(table = tb.table :+ t)
}
}
}
diff --git a/src/main/scala/chisel3/util/experimental/decode/TruthTable.scala b/src/main/scala/chisel3/util/experimental/decode/TruthTable.scala
index 683de16b..322466f9 100644
--- a/src/main/scala/chisel3/util/experimental/decode/TruthTable.scala
+++ b/src/main/scala/chisel3/util/experimental/decode/TruthTable.scala
@@ -4,8 +4,7 @@ package chisel3.util.experimental.decode
import chisel3.util.BitPat
-final class TruthTable(val table: Map[BitPat, BitPat], val default: BitPat) {
-
+sealed class TruthTable private (val table: Seq[(BitPat, BitPat)], val default: BitPat, val sort: Boolean) {
def inputWidth = table.head._1.getWidth
def outputWidth = table.head._2.getWidth
@@ -14,10 +13,10 @@ final class TruthTable(val table: Map[BitPat, BitPat], val default: BitPat) {
def writeRow(map: (BitPat, BitPat)): String =
s"${map._1.rawString}->${map._2.rawString}"
- (table.map(writeRow) ++ Seq(s"${" "*(inputWidth + 2)}${default.rawString}")).toSeq.sorted.mkString("\n")
+ (table.map(writeRow) ++ Seq(s"${" "*(inputWidth + 2)}${default.rawString}")).mkString("\n")
}
- def copy(table: Map[BitPat, BitPat] = this.table, default: BitPat = this.default) = new TruthTable(table, default)
+ def copy(table: Seq[(BitPat, BitPat)] = this.table, default: BitPat = this.default, sort: Boolean = this.sort) = TruthTable(table, default, sort)
override def equals(y: Any): Boolean = {
y match {
@@ -28,25 +27,12 @@ final class TruthTable(val table: Map[BitPat, BitPat], val default: BitPat) {
}
object TruthTable {
- /** Parse TruthTable from its string representation. */
- def apply(tableString: String): TruthTable = {
- TruthTable(
- tableString
- .split("\n")
- .filter(_.contains("->"))
- .map(_.split("->").map(str => BitPat(s"b$str")))
- .map(bps => bps(0) -> bps(1))
- .toSeq,
- BitPat(s"b${tableString.split("\n").filterNot(_.contains("->")).head.replace(" ", "")}")
- )
- }
-
/** Convert a table and default output into a [[TruthTable]]. */
- def apply(table: Iterable[(BitPat, BitPat)], default: BitPat): TruthTable = {
+ def apply(table: Iterable[(BitPat, BitPat)], default: BitPat, sort: Boolean = true): TruthTable = {
require(table.map(_._1.getWidth).toSet.size == 1, "input width not equal.")
require(table.map(_._2.getWidth).toSet.size == 1, "output width not equal.")
val outputWidth = table.map(_._2.getWidth).head
- new TruthTable(table.toSeq.groupBy(_._1.toString).map { case (key, values) =>
+ val mergedTable = table.groupBy(_._1.toString).map { case (key, values) =>
// merge same input inputs.
values.head._1 -> BitPat(s"b${
Seq.tabulate(outputWidth) { i =>
@@ -59,9 +45,23 @@ object TruthTable {
outputSet.headOption.getOrElse('?')
}.mkString
}")
- }, default)
+ }.toSeq
+ import BitPat.bitPatOrder
+ new TruthTable(if(sort) mergedTable.sorted else mergedTable, default, sort)
}
+ /** Parse TruthTable from its string representation. */
+ def fromString(tableString: String): TruthTable = {
+ TruthTable(
+ tableString
+ .split("\n")
+ .filter(_.contains("->"))
+ .map(_.split("->").map(str => BitPat(s"b$str")))
+ .map(bps => bps(0) -> bps(1))
+ .toSeq,
+ BitPat(s"b${tableString.split("\n").filterNot(_.contains("->")).head.replace(" ", "")}")
+ )
+ }
/** consume 1 table, split it into up to 3 tables with the same default bits.
*
@@ -99,18 +99,17 @@ object TruthTable {
tables: Seq[(TruthTable, Seq[Int])]
): TruthTable = {
def reIndex(bitPat: BitPat, table: TruthTable, indexes: Seq[Int]): Seq[(Char, Int)] =
- (table.table.map(a => a._1.toString -> a._2).getOrElse(bitPat.toString, BitPat.dontCare(indexes.size))).rawString.zip(indexes)
+ table.table.map(a => a._1.toString -> a._2).collectFirst{ case (k, v) if k == bitPat.toString => v}.getOrElse(BitPat.dontCare(indexes.size)).rawString.zip(indexes)
def bitPat(indexedChar: Seq[(Char, Int)]) = BitPat(s"b${indexedChar
.sortBy(_._2)
.map(_._1)
.mkString}")
TruthTable(
tables
- .flatMap(_._1.table.keys)
+ .flatMap(_._1.table.map(_._1))
.map { key =>
key -> bitPat(tables.flatMap { case (table, indexes) => reIndex(key, table, indexes) })
- }
- .toMap,
+ },
bitPat(tables.flatMap { case (table, indexes) => table.default.rawString.zip(indexes) })
)
}
diff --git a/src/main/scala/chisel3/util/experimental/decode/decoder.scala b/src/main/scala/chisel3/util/experimental/decode/decoder.scala
index 42e374d1..e0bf83b2 100644
--- a/src/main/scala/chisel3/util/experimental/decode/decoder.scala
+++ b/src/main/scala/chisel3/util/experimental/decode/decoder.scala
@@ -5,7 +5,7 @@ package chisel3.util.experimental.decode
import chisel3._
import chisel3.experimental.{ChiselAnnotation, annotate}
import chisel3.util.{BitPat, pla}
-import chisel3.util.experimental.getAnnotations
+import chisel3.util.experimental.{BitSet, getAnnotations}
import firrtl.annotations.Annotation
import logger.LazyLogging
@@ -19,7 +19,7 @@ object decoder extends LazyLogging {
*/
def apply(minimizer: Minimizer, input: UInt, truthTable: TruthTable): UInt = {
val minimizedTable = getAnnotations().collect {
- case DecodeTableAnnotation(_, in, out) => TruthTable(in) -> TruthTable(out)
+ case DecodeTableAnnotation(_, in, out) => TruthTable.fromString(in) -> TruthTable.fromString(out)
}.toMap.getOrElse(truthTable, minimizer.minimize(truthTable))
if (minimizedTable.table.isEmpty) {
val outputs = Wire(UInt(minimizedTable.default.getWidth.W))
@@ -80,4 +80,35 @@ object decoder extends LazyLogging {
qmcFallBack(input, truthTable)
}
}
+
+
+ /** Generate a decoder circuit that matches the input to each bitSet.
+ *
+ * The resulting circuit functions like the following but is optimized with a logic minifier.
+ * {{{
+ * when(input === bitSets(0)) { output := b000001 }
+ * .elsewhen (input === bitSets(1)) { output := b000010 }
+ * ....
+ * .otherwise { if (errorBit) output := b100000 else output := DontCare }
+ * }}}
+ *
+ * @param input input to the decoder circuit, width should be equal to bitSets.width
+ * @param bitSets set of ports to be matched, all width should be the equal
+ * @param errorBit whether generate an additional decode error bit at MSB of output.
+ * @return decoded wire
+ */
+ def bitset(input: chisel3.UInt, bitSets: Seq[BitSet], errorBit: Boolean = false): chisel3.UInt =
+ chisel3.util.experimental.decode.decoder(
+ input,
+ chisel3.util.experimental.decode.TruthTable.fromString(
+ {
+ 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}")
+ }.mkString("\n")
+ )
+ )
}
diff --git a/src/main/scala/chisel3/util/random/GaloisLFSR.scala b/src/main/scala/chisel3/util/random/GaloisLFSR.scala
index 0d407c87..68346e82 100644
--- a/src/main/scala/chisel3/util/random/GaloisLFSR.scala
+++ b/src/main/scala/chisel3/util/random/GaloisLFSR.scala
@@ -13,7 +13,7 @@ import chisel3._
*
* $seedExplanation
*
- * In the example below, a 4-bit LFSR Fibonacci LFSR is constructed. The tap points are defined as four and three
+ * In the example below, a 4-bit LFSR Galois LFSR is constructed. The tap points are defined as four and three
* (using LFSR convention of indexing from one). This results in the hardware configuration shown in the diagram.
*
* {{{
@@ -85,7 +85,7 @@ class MaxPeriodGaloisLFSR(width: Int, seed: Option[BigInt] = Some(1), reduction:
*/
object GaloisLFSR {
- /** Return a pseudorandom [[UInt]] generated from a [[FibonacciLFSR]].
+ /** Return a pseudorandom [[UInt]] generated from a [[GaloisLFSR]].
* $paramWidth
* $paramTaps
* $paramIncrement
diff --git a/src/main/scala/chisel3/util/random/PRNG.scala b/src/main/scala/chisel3/util/random/PRNG.scala
index d94b78e8..3a44385a 100644
--- a/src/main/scala/chisel3/util/random/PRNG.scala
+++ b/src/main/scala/chisel3/util/random/PRNG.scala
@@ -7,16 +7,23 @@ import chisel3.util.Valid
/** Pseudo Random Number Generators (PRNG) interface
* @param n the width of the LFSR
+ * @groupdesc Signals The actual hardware fields of the Bundle
*/
class PRNGIO(val n: Int) extends Bundle {
- /** A [[chisel3.util.Valid Valid]] interface that can be used to set the seed (internal PRNG state) */
+ /** A [[chisel3.util.Valid Valid]] interface that can be used to set the seed (internal PRNG state)
+ * @group Signals
+ */
val seed: Valid[Vec[Bool]] = Input(Valid(Vec(n, Bool())))
- /** When asserted, the PRNG will increment by one */
+ /** When asserted, the PRNG will increment by one
+ * @group Signals
+ */
val increment: Bool = Input(Bool())
- /** The current state of the PRNG */
+ /** The current state of the PRNG
+ * @group Signals
+ */
val out: Vec[Bool] = Output(Vec(n, Bool()))
}
@@ -62,7 +69,7 @@ abstract class PRNG(val width: Int, val seed: Option[BigInt], step: Int = 1, upd
state := nextState(state)
}
- when (io.seed.fire()) {
+ when (io.seed.fire) {
state := (if (updateSeed) { nextState(io.seed.bits) } else { io.seed.bits })
}
diff --git a/src/test/scala/chisel3/testers/TestUtils.scala b/src/test/scala/chisel3/testers/TestUtils.scala
index c72c779a..338f9cd4 100644
--- a/src/test/scala/chisel3/testers/TestUtils.scala
+++ b/src/test/scala/chisel3/testers/TestUtils.scala
@@ -12,13 +12,4 @@ object TestUtils {
// Useful because TesterDriver.Backend is chisel3 package private
def containsBackend(annos: AnnotationSeq): Boolean =
annos.collectFirst { case b: Backend => b }.isDefined
-
- // Allows us to check that the compiler plugin cloneType is actually working
- val usingPlugin: Boolean = (new Bundle { def check = _usingPlugin }).check
- def elaborateNoReflectiveAutoCloneType(f: => RawModule): Circuit = {
- ChiselStage.elaborate {
- chisel3.internal.Builder.allowReflectiveAutoCloneType = !usingPlugin
- f
- }
- }
}
diff --git a/src/test/scala/chiselTests/AutoClonetypeSpec.scala b/src/test/scala/chiselTests/AutoClonetypeSpec.scala
index fcbc4785..ef58f1ed 100644
--- a/src/test/scala/chiselTests/AutoClonetypeSpec.scala
+++ b/src/test/scala/chiselTests/AutoClonetypeSpec.scala
@@ -5,6 +5,7 @@ package chiselTests
import chisel3._
import chisel3.testers.TestUtils
import chisel3.util.QueueIO
+import chisel3.stage.ChiselStage.elaborate
class BundleWithIntArg(val i: Int) extends Bundle {
val out = UInt(i.W)
@@ -71,14 +72,11 @@ class InheritingBundle extends QueueIO(UInt(8.W), 8) {
val error = Output(Bool())
}
-// TODO all `.suggestNames` are due to https://github.com/chipsalliance/chisel3/issues/1802
class AutoClonetypeSpec extends ChiselFlatSpec with Utils {
- val usingPlugin: Boolean = TestUtils.usingPlugin
- val elaborate = TestUtils.elaborateNoReflectiveAutoCloneType _
"Bundles with Scala args" should "not need clonetype" in {
elaborate { new Module {
- val io = IO(new Bundle{}).suggestName("io")
+ val io = IO(new Bundle{})
val myWire = Wire(new BundleWithIntArg(8))
assert(myWire.i == 8)
@@ -87,7 +85,7 @@ class AutoClonetypeSpec extends ChiselFlatSpec with Utils {
"Bundles with Scala implicit args" should "not need clonetype" in {
elaborate { new Module {
- val io = IO(new Bundle{}).suggestName("io")
+ val io = IO(new Bundle{})
implicit val implicitInt: Int = 4
val myWire = Wire(new BundleWithImplicit())
@@ -98,7 +96,7 @@ class AutoClonetypeSpec extends ChiselFlatSpec with Utils {
"Bundles with Scala explicit and impicit args" should "not need clonetype" in {
elaborate { new Module {
- val io = IO(new Bundle{}).suggestName("io")
+ val io = IO(new Bundle{})
implicit val implicitInt: Int = 4
val myWire = Wire(new BundleWithArgAndImplicit(8))
@@ -110,7 +108,7 @@ class AutoClonetypeSpec extends ChiselFlatSpec with Utils {
"Subtyped Bundles" should "not need clonetype" in {
elaborate { new Module {
- val io = IO(new Bundle{}).suggestName("io")
+ val io = IO(new Bundle{})
val myWire = Wire(new SubBundle(8, 4))
@@ -118,7 +116,7 @@ class AutoClonetypeSpec extends ChiselFlatSpec with Utils {
assert(myWire.i2 == 4)
} }
elaborate { new Module {
- val io = IO(new Bundle{}).suggestName("io")
+ val io = IO(new Bundle{})
val myWire = Wire(new SubBundleVal(8, 4))
@@ -131,23 +129,12 @@ class AutoClonetypeSpec extends ChiselFlatSpec with Utils {
new BundleWithIntArg(8).cloneType
}
- def checkSubBundleInvalid() = {
+ "Subtyped Bundles that don't clone well" should "be now be supported!" in {
elaborate { new Module {
- val io = IO(new Bundle{}).suggestName("io")
+ val io = IO(new Bundle{})
val myWire = Wire(new SubBundleInvalid(8, 4))
} }
}
- if (usingPlugin) {
- "Subtyped Bundles that don't clone well" should "be now be supported!" in {
- checkSubBundleInvalid()
- }
- } else {
- "Subtyped Bundles that don't clone well" should "be caught" in {
- a [ChiselException] should be thrownBy extractCause[ChiselException] {
- checkSubBundleInvalid()
- }
- }
- }
"Inner bundles with Scala args" should "not need clonetype" in {
elaborate { new ModuleWithInner }
@@ -155,7 +142,7 @@ class AutoClonetypeSpec extends ChiselFlatSpec with Utils {
"Bundles with arguments as fields" should "not need clonetype" in {
elaborate { new Module {
- val io = IO(Output(new BundleWithArgumentField(UInt(8.W), UInt(8.W)))).suggestName("io")
+ val io = IO(Output(new BundleWithArgumentField(UInt(8.W), UInt(8.W))))
io.x := 1.U
io.y := 1.U
} }
@@ -163,28 +150,28 @@ class AutoClonetypeSpec extends ChiselFlatSpec with Utils {
it should "also work when giving directions to the fields" in {
elaborate { new Module {
- val io = IO(new BundleWithArgumentField(Input(UInt(8.W)), Output(UInt(8.W)))).suggestName("io")
+ val io = IO(new BundleWithArgumentField(Input(UInt(8.W)), Output(UInt(8.W))))
io.y := io.x
} }
}
"Bundles inside companion objects" should "not need clonetype" in {
elaborate { new Module {
- val io = IO(Output(new CompanionObjectWithBundle.Inner)).suggestName("io")
+ val io = IO(Output(new CompanionObjectWithBundle.Inner))
io.data := 1.U
} }
}
"Parameterized bundles inside companion objects" should "not need clonetype" in {
elaborate { new Module {
- val io = IO(Output(new CompanionObjectWithBundle.ParameterizedInner(8))).suggestName("io")
+ val io = IO(Output(new CompanionObjectWithBundle.ParameterizedInner(8)))
io.data := 1.U
} }
}
"Nested directioned anonymous Bundles" should "not need clonetype" in {
elaborate { new Module {
- val io = IO(new NestedAnonymousBundle).suggestName("io")
+ val io = IO(new NestedAnonymousBundle)
val a = WireDefault(io)
io.a.a := 1.U
} }
@@ -197,7 +184,7 @@ class AutoClonetypeSpec extends ChiselFlatSpec with Utils {
val a = Output(UInt(8.W))
}
}
- val io = IO((new InnerClassThing).createBundle).suggestName("io")
+ val io = IO((new InnerClassThing).createBundle)
val a = WireDefault(io)
} }
}
@@ -208,7 +195,7 @@ class AutoClonetypeSpec extends ChiselFlatSpec with Utils {
val bundleFieldType = UInt(8.W)
val io = IO(Output(new Bundle {
val a = bundleFieldType
- })).suggestName("io")
+ }))
io.a := 0.U
} }
}
@@ -221,7 +208,7 @@ class AutoClonetypeSpec extends ChiselFlatSpec with Utils {
}
elaborate { new Module {
- val io = IO(Output(new BadBundle(UInt(8.W), 1))).suggestName("io")
+ val io = IO(Output(new BadBundle(UInt(8.W), 1)))
io.a := 0.U
} }
}
@@ -265,101 +252,97 @@ class AutoClonetypeSpec extends ChiselFlatSpec with Utils {
behavior of "Compiler Plugin Autoclonetype"
- // New tests from the plugin
- if (usingPlugin) {
- it should "NOT break code that extends chisel3.util Bundles if they use the plugin" in {
- class MyModule extends MultiIOModule {
- val io = IO(new InheritingBundle)
- io.deq <> io.enq
- io.count := 0.U
- io.error := true.B
- }
- elaborate(new MyModule)
+ it should "NOT break code that extends chisel3.util Bundles if they use the plugin" in {
+ class MyModule extends MultiIOModule {
+ val io = IO(new InheritingBundle)
+ io.deq <> io.enq
+ io.count := 0.U
+ io.error := true.B
}
+ elaborate(new MyModule)
+ }
- it should "support Bundles with non-val parameters" in {
- class MyBundle(i: Int) extends Bundle {
- val foo = UInt(i.W)
- }
- elaborate { new MultiIOModule {
- val in = IO(Input(new MyBundle(8)))
- val out = IO(Output(new MyBundle(8)))
- out := in
- }}
+ it should "support Bundles with non-val parameters" in {
+ class MyBundle(i: Int) extends Bundle {
+ val foo = UInt(i.W)
}
+ elaborate { new MultiIOModule {
+ val in = IO(Input(new MyBundle(8)))
+ val out = IO(Output(new MyBundle(8)))
+ out := in
+ }}
+ }
- it should "support type-parameterized Bundles" in {
- class MyBundle[T <: Data](gen: T) extends Bundle {
- val foo = gen
- }
- elaborate { new MultiIOModule {
- val in = IO(Input(new MyBundle(UInt(8.W))))
- val out = IO(Output(new MyBundle(UInt(8.W))))
- out := in
- }}
+ it should "support type-parameterized Bundles" in {
+ class MyBundle[T <: Data](gen: T) extends Bundle {
+ val foo = gen
}
+ elaborate { new MultiIOModule {
+ val in = IO(Input(new MyBundle(UInt(8.W))))
+ val out = IO(Output(new MyBundle(UInt(8.W))))
+ out := in
+ }}
+ }
- it should "support Bundles with non-val implicit parameters" in {
- class MyBundle(implicit i: Int) extends Bundle {
- val foo = UInt(i.W)
- }
- elaborate { new MultiIOModule {
- implicit val x = 8
- val in = IO(Input(new MyBundle))
- val out = IO(Output(new MyBundle))
- out := in
- }}
+ it should "support Bundles with non-val implicit parameters" in {
+ class MyBundle(implicit i: Int) extends Bundle {
+ val foo = UInt(i.W)
}
+ elaborate { new MultiIOModule {
+ implicit val x = 8
+ val in = IO(Input(new MyBundle))
+ val out = IO(Output(new MyBundle))
+ out := in
+ }}
+ }
- it should "support Bundles with multiple parameter lists" in {
- class MyBundle(i: Int)(j: Int, jj: Int)(k: UInt) extends Bundle {
- val foo = UInt((i + j + jj + k.getWidth).W)
- }
- elaborate {
- new MultiIOModule {
- val in = IO(Input(new MyBundle(8)(8, 8)(UInt(8.W))))
- val out = IO(Output(new MyBundle(8)(8, 8)(UInt(8.W))))
- out := in
- }
+ it should "support Bundles with multiple parameter lists" in {
+ class MyBundle(i: Int)(j: Int, jj: Int)(k: UInt) extends Bundle {
+ val foo = UInt((i + j + jj + k.getWidth).W)
+ }
+ elaborate {
+ new MultiIOModule {
+ val in = IO(Input(new MyBundle(8)(8, 8)(UInt(8.W))))
+ val out = IO(Output(new MyBundle(8)(8, 8)(UInt(8.W))))
+ out := in
}
}
+ }
- it should "support Bundles that implement their own cloneType" in {
- class MyBundle(i: Int) extends Bundle {
- val foo = UInt(i.W)
- override def cloneType = new MyBundle(i).asInstanceOf[this.type]
- }
- elaborate { new MultiIOModule {
- val in = IO(Input(new MyBundle(8)))
- val out = IO(Output(new MyBundle(8)))
- out := in
- }}
+ it should "support Bundles that implement their own cloneType" in {
+ class MyBundle(i: Int) extends Bundle {
+ val foo = UInt(i.W)
}
+ elaborate { new MultiIOModule {
+ val in = IO(Input(new MyBundle(8)))
+ val out = IO(Output(new MyBundle(8)))
+ out := in
+ }}
+ }
- it should "support Bundles that capture type parameters from their parent scope" in {
- class MyModule[T <: Data](gen: T) extends MultiIOModule {
- class MyBundle(n: Int) extends Bundle {
- val foo = Vec(n, gen)
- }
- val in = IO(Input(new MyBundle(4)))
- val out = IO(Output(new MyBundle(4)))
- out := in
+ it should "support Bundles that capture type parameters from their parent scope" in {
+ class MyModule[T <: Data](gen: T) extends MultiIOModule {
+ class MyBundle(n: Int) extends Bundle {
+ val foo = Vec(n, gen)
}
- elaborate(new MyModule(UInt(8.W)))
+ val in = IO(Input(new MyBundle(4)))
+ val out = IO(Output(new MyBundle(4)))
+ out := in
}
+ elaborate(new MyModule(UInt(8.W)))
+ }
- it should "work for higher-kinded types" in {
- class DataGen[T <: Data](gen: T) {
- def newType: T = gen.cloneType
- }
- class MyBundle[A <: Data, B <: DataGen[A]](gen: B) extends Bundle {
- val foo = gen.newType
- }
- class MyModule extends MultiIOModule {
- val io = IO(Output(new MyBundle[UInt, DataGen[UInt]](new DataGen(UInt(3.W)))))
- io.foo := 0.U
- }
- elaborate(new MyModule)
+ it should "work for higher-kinded types" in {
+ class DataGen[T <: Data](gen: T) {
+ def newType: T = gen.cloneType
+ }
+ class MyBundle[A <: Data, B <: DataGen[A]](gen: B) extends Bundle {
+ val foo = gen.newType
+ }
+ class MyModule extends MultiIOModule {
+ val io = IO(Output(new MyBundle[UInt, DataGen[UInt]](new DataGen(UInt(3.W)))))
+ io.foo := 0.U
}
+ elaborate(new MyModule)
}
}
diff --git a/src/test/scala/chiselTests/AutoNestedCloneSpec.scala b/src/test/scala/chiselTests/AutoNestedCloneSpec.scala
index 401766e2..258d0823 100644
--- a/src/test/scala/chiselTests/AutoNestedCloneSpec.scala
+++ b/src/test/scala/chiselTests/AutoNestedCloneSpec.scala
@@ -3,6 +3,7 @@
package chiselTests
import chisel3._
import chisel3.testers.TestUtils
+import chisel3.stage.ChiselStage.elaborate
import org.scalatest.matchers.should.Matchers
class BundleWithAnonymousInner(val w: Int) extends Bundle {
@@ -11,10 +12,7 @@ class BundleWithAnonymousInner(val w: Int) extends Bundle {
}
}
-// TODO all `.suggestNames` are due to https://github.com/chipsalliance/chisel3/issues/1802
class AutoNestedCloneSpec extends ChiselFlatSpec with Matchers with Utils {
- val usingPlugin: Boolean = TestUtils.usingPlugin
- val elaborate = TestUtils.elaborateNoReflectiveAutoCloneType _
behavior of "autoCloneType of inner Bundle in Chisel3"
@@ -27,7 +25,7 @@ class AutoNestedCloneSpec extends ChiselFlatSpec with Matchers with Utils {
}
def getIO: InnerIOType = new InnerIOType
}
- val io = IO(new Bundle {}).suggestName("io")
+ val io = IO(new Bundle {})
val myWire = Wire((new Middle(w)).getIO)
}
new Outer(2)
@@ -37,7 +35,7 @@ class AutoNestedCloneSpec extends ChiselFlatSpec with Matchers with Utils {
it should "clone an anonymous inner bundle successfully" in {
elaborate {
class TestTop(val w: Int) extends Module {
- val io = IO(new Bundle {}).suggestName("io")
+ val io = IO(new Bundle {})
val myWire = Wire(new Bundle{ val a = UInt(w.W) })
}
new TestTop(2)
@@ -50,13 +48,13 @@ class AutoNestedCloneSpec extends ChiselFlatSpec with Matchers with Utils {
val io = IO(new Bundle{
val in = Input(UInt(w.W))
val out = Output(UInt(w.W))
- }).suggestName("io")
+ })
}
class Outer(val w: Int) extends Module {
val io = IO(new Bundle{
val in = Input(UInt(w.W))
val out = Output(UInt(w.W))
- }).suggestName("io")
+ })
val i = Module(new Inner(w))
val iw = Wire(chiselTypeOf(i.io))
iw <> io
@@ -69,7 +67,7 @@ class AutoNestedCloneSpec extends ChiselFlatSpec with Matchers with Utils {
it should "clone an anonymous, bound, inner bundle of another bundle successfully" in {
elaborate {
class TestModule(w: Int) extends Module {
- val io = IO(new BundleWithAnonymousInner(w) ).suggestName("io")
+ val io = IO(new BundleWithAnonymousInner(w))
val w0 = WireDefault(io)
val w1 = WireDefault(io.inner)
}
@@ -85,7 +83,7 @@ class AutoNestedCloneSpec extends ChiselFlatSpec with Matchers with Utils {
}
val io = IO(new Bundle {
val inner = Input(bun)
- }).suggestName("io")
+ })
val w0 = WireDefault(io)
val w1 = WireDefault(io.inner)
}
@@ -100,42 +98,39 @@ class AutoNestedCloneSpec extends ChiselFlatSpec with Matchers with Utils {
val inner = Input(new Bundle {
val x = UInt(8.W)
})
- }).suggestName("io")
+ })
}
new TestModule()
}
}
- if (usingPlugin) {
- // This works with the plugin, but is a null pointer exception when using reflective autoclonetype
- it should "support an anonymous doubly-nested inner bundle" in {
- elaborate {
- class Outer(val w: Int) extends Module {
- class Middle(val w: Int) {
- def getIO: Bundle = new Bundle {
- val in = Input(UInt(w.W))
- }
+ it should "support an anonymous doubly-nested inner bundle" in {
+ elaborate {
+ class Outer(val w: Int) extends Module {
+ class Middle(val w: Int) {
+ def getIO: Bundle = new Bundle {
+ val in = Input(UInt(w.W))
}
- val io = IO(new Bundle {}).suggestName("io")
- val myWire = Wire((new Middle(w)).getIO)
}
- new Outer(2)
+ val io = IO(new Bundle {})
+ val myWire = Wire((new Middle(w)).getIO)
}
+ new Outer(2)
}
+ }
- it should "support anonymous Inner bundles that capture type parameters from outer Bundles" in {
- elaborate(new MultiIOModule {
- class MyBundle[T <: Data](n: Int, gen: T) extends Bundle {
- val foo = new Bundle {
- val x = Input(Vec(n, gen))
- }
- val bar = Output(Option(new { def mkBundle = new Bundle { val x = Vec(n, gen) }}).get.mkBundle)
+ it should "support anonymous Inner bundles that capture type parameters from outer Bundles" in {
+ elaborate(new MultiIOModule {
+ class MyBundle[T <: Data](n: Int, gen: T) extends Bundle {
+ val foo = new Bundle {
+ val x = Input(Vec(n, gen))
}
- val io = IO(new MyBundle(4, UInt(8.W)))
- val myWire = WireInit(io.foo)
- val myWire2 = WireInit(io.bar)
- io.bar.x := io.foo.x
- })
- }
+ val bar = Output(Option(new { def mkBundle = new Bundle { val x = Vec(n, gen) }}).get.mkBundle)
+ }
+ val io = IO(new MyBundle(4, UInt(8.W)))
+ val myWire = WireInit(io.foo)
+ val myWire2 = WireInit(io.bar)
+ io.bar.x := io.foo.x
+ })
}
}
diff --git a/src/test/scala/chiselTests/BlackBoxImpl.scala b/src/test/scala/chiselTests/BlackBoxImpl.scala
index a9a6fa29..2fa3d8a6 100644
--- a/src/test/scala/chiselTests/BlackBoxImpl.scala
+++ b/src/test/scala/chiselTests/BlackBoxImpl.scala
@@ -7,7 +7,6 @@ import java.io.File
import chisel3._
import chisel3.util.{HasBlackBoxInline, HasBlackBoxResource, HasBlackBoxPath}
import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage}
-import firrtl.FirrtlExecutionSuccess
import firrtl.transforms.BlackBoxNotFoundException
import org.scalacheck.Test.Failed
import org.scalatest.Succeeded
diff --git a/src/test/scala/chiselTests/BundleSpec.scala b/src/test/scala/chiselTests/BundleSpec.scala
index 1d392f5c..d9f82e6d 100644
--- a/src/test/scala/chiselTests/BundleSpec.scala
+++ b/src/test/scala/chiselTests/BundleSpec.scala
@@ -10,25 +10,20 @@ trait BundleSpecUtils {
class BundleFooBar extends Bundle {
val foo = UInt(16.W)
val bar = UInt(16.W)
- override def cloneType: this.type = (new BundleFooBar).asInstanceOf[this.type]
}
class BundleBarFoo extends Bundle {
val bar = UInt(16.W)
val foo = UInt(16.W)
- override def cloneType: this.type = (new BundleBarFoo).asInstanceOf[this.type]
}
class BundleFoo extends Bundle {
val foo = UInt(16.W)
- override def cloneType: this.type = (new BundleFoo).asInstanceOf[this.type]
}
class BundleBar extends Bundle {
val bar = UInt(16.W)
- override def cloneType: this.type = (new BundleBar).asInstanceOf[this.type]
}
class BadSeqBundle extends Bundle {
val bar = Seq(UInt(16.W), UInt(8.W), UInt(4.W))
- override def cloneType: this.type = (new BadSeqBundle).asInstanceOf[this.type]
}
class MyModule(output: Bundle, input: Bundle) extends Module {
@@ -116,17 +111,21 @@ class BundleSpec extends ChiselFlatSpec with BundleSpecUtils with Utils {
}
}
- "Bundles" should "not have aliased fields" in {
+ "Bundles" should "with aliased fields, should show a helpful error message" in {
+ class AliasedBundle extends Bundle {
+ val a = UInt(8.W)
+ val b = a
+ val c = SInt(8.W)
+ val d = c
+ }
+
(the[ChiselException] thrownBy extractCause[ChiselException] {
ChiselStage.elaborate { new Module {
- val io = IO(Output(new Bundle {
- val a = UInt(8.W)
- val b = a
- }))
+ val io = IO(Output(new AliasedBundle))
io.a := 0.U
io.b := 1.U
} }
- }).getMessage should include("aliased fields")
+ }).getMessage should include("contains aliased fields named (a,b),(c,d)")
}
"Bundles" should "not have bound hardware" in {
@@ -162,4 +161,16 @@ class BundleSpec extends ChiselFlatSpec with BundleSpecUtils with Utils {
}
}
}
+
+ // This tests the interaction of override def cloneType and the plugin.
+ // We are commenting it for now because although this code fails to compile
+ // as expected when just copied here, the test version is not seeing the failure.
+ // """
+ // class BundleBaz(w: Int) extends Bundle {
+ // val baz = UInt(w.W)
+ // // This is a compiler error when using the plugin, which we test below.
+ // override def cloneType = (new BundleBaz(w)).asInstanceOf[this.type]
+ // }
+ // """ shouldNot compile
+
}
diff --git a/src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala b/src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala
index 1795cc1f..4b03dfa5 100644
--- a/src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala
+++ b/src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala
@@ -12,8 +12,6 @@ object CompatibilityComponents {
class ChiselBundle extends Bundle {
val a = UInt(width = 32)
val b = UInt(width = 32).flip
-
- override def cloneType: this.type = (new ChiselBundle).asInstanceOf[this.type]
}
class ChiselRecord extends Record {
val elements = ListMap("a" -> UInt(width = 32), "b" -> UInt(width = 32).flip)
@@ -48,8 +46,6 @@ object Chisel3Components {
class Chisel3Bundle extends Bundle {
val a = Output(UInt(32.W))
val b = Input(UInt(32.W))
-
- override def cloneType: this.type = (new Chisel3Bundle).asInstanceOf[this.type]
}
class Chisel3Record extends Record {
@@ -341,7 +337,6 @@ class CompatibiltyInteroperabilitySpec extends ChiselFlatSpec {
val foo = maybeFlip(new Bundle {
val bar = UInt(INPUT, width = 8)
})
- override def cloneType = (new MyBundle(extraFlip)).asInstanceOf[this.type]
}
}
import chisel3._
diff --git a/src/test/scala/chiselTests/CompatibilitySpec.scala b/src/test/scala/chiselTests/CompatibilitySpec.scala
index 2d4ad517..7ac67b7c 100644
--- a/src/test/scala/chiselTests/CompatibilitySpec.scala
+++ b/src/test/scala/chiselTests/CompatibilitySpec.scala
@@ -195,11 +195,9 @@ class CompatibiltySpec extends ChiselFlatSpec with ScalaCheckDrivenPropertyCheck
class SmallBundle extends Bundle {
val f1 = UInt(width = 4)
val f2 = UInt(width = 5)
- override def cloneType: this.type = (new SmallBundle).asInstanceOf[this.type]
}
class BigBundle extends SmallBundle {
val f3 = UInt(width = 6)
- override def cloneType: this.type = (new BigBundle).asInstanceOf[this.type]
}
"A Module with missing bundle fields when compiled with the Chisel compatibility package" should "not throw an exception" in {
@@ -538,6 +536,9 @@ class CompatibiltySpec extends ChiselFlatSpec with ScalaCheckDrivenPropertyCheck
info("toUInt works")
s.toUInt shouldBe a [UInt]
+
+ info("toBools works")
+ s.toBools shouldBe a [Seq[Bool]]
}
ChiselStage.elaborate(new Foo)
@@ -566,4 +567,32 @@ class CompatibiltySpec extends ChiselFlatSpec with ScalaCheckDrivenPropertyCheck
verilog should include ("assign io_out_0 = io_in_0;")
}
+ it should "ignore .suggestName on field io" in {
+ class MyModule extends Module {
+ val io = new Bundle {
+ val foo = UInt(width = 8).asInput
+ val bar = UInt(width = 8).asOutput
+ }
+ io.suggestName("potato")
+ io.bar := io.foo
+ }
+ val verilog = ChiselStage.emitVerilog(new MyModule)
+ verilog should include ("input [7:0] io_foo")
+ verilog should include ("output [7:0] io_bar")
+ }
+
+ it should "properly name field io" in {
+ class MyModule extends Module {
+ val io = new Bundle {
+ val foo = UInt(width = 8).asInput
+ val bar = UInt(width = 8).asOutput
+ }
+ val wire = Wire(init = io.foo)
+ io.bar := wire
+ }
+ val verilog = ChiselStage.emitVerilog(new MyModule)
+ verilog should include ("input [7:0] io_foo")
+ verilog should include ("output [7:0] io_bar")
+ }
+
}
diff --git a/src/test/scala/chiselTests/CompileOptionsTest.scala b/src/test/scala/chiselTests/CompileOptionsTest.scala
index 9c88c1e0..1ecf97f0 100644
--- a/src/test/scala/chiselTests/CompileOptionsTest.scala
+++ b/src/test/scala/chiselTests/CompileOptionsTest.scala
@@ -14,11 +14,9 @@ class CompileOptionsSpec extends ChiselFlatSpec with Utils {
class SmallBundle extends Bundle {
val f1 = UInt(4.W)
val f2 = UInt(5.W)
- override def cloneType: this.type = (new SmallBundle).asInstanceOf[this.type]
}
class BigBundle extends SmallBundle {
val f3 = UInt(6.W)
- override def cloneType: this.type = (new BigBundle).asInstanceOf[this.type]
}
"A Module with missing bundle fields when compiled with implicit Strict.CompileOption " should "throw an exception" in {
diff --git a/src/test/scala/chiselTests/ComplexAssign.scala b/src/test/scala/chiselTests/ComplexAssign.scala
index 36fb59c2..222b6373 100644
--- a/src/test/scala/chiselTests/ComplexAssign.scala
+++ b/src/test/scala/chiselTests/ComplexAssign.scala
@@ -7,10 +7,7 @@ import chisel3.testers.BasicTester
import chisel3.util._
import org.scalacheck.Shrink
-class Complex[T <: Data](val re: T, val im: T) extends Bundle {
- override def cloneType: this.type =
- new Complex(re.cloneType, im.cloneType).asInstanceOf[this.type]
-}
+class Complex[T <: Data](val re: T, val im: T) extends Bundle
class ComplexAssign(w: Int) extends Module {
val io = IO(new Bundle {
diff --git a/src/test/scala/chiselTests/ConnectSpec.scala b/src/test/scala/chiselTests/ConnectSpec.scala
index 367864e6..f9ef5946 100644
--- a/src/test/scala/chiselTests/ConnectSpec.scala
+++ b/src/test/scala/chiselTests/ConnectSpec.scala
@@ -2,6 +2,8 @@
package chiselTests
+import org.scalatest._
+
import chisel3._
import chisel3.experimental.{Analog, FixedPoint}
import chisel3.stage.ChiselStage
@@ -126,4 +128,37 @@ class ConnectSpec extends ChiselPropSpec with Utils {
property("Pipe internal connections should succeed") {
ChiselStage.elaborate( new PipeInternalWires)
}
+
+ property("Connect error messages should have meaningful information") {
+ class InnerExample extends Module {
+ val myReg = RegInit(0.U(8.W))
+ }
+
+ class OuterAssignExample extends Module {
+ val inner = Module(new InnerExample())
+ inner.myReg := false.B // ERROR
+ }
+
+ val assignError = the [ChiselException] thrownBy {ChiselStage.elaborate { new OuterAssignExample}}
+ val expectedAssignError = """.*@: myReg in InnerExample cannot be written from module OuterAssignExample."""
+ assignError.getMessage should fullyMatch regex expectedAssignError
+
+ class OuterReadExample extends Module {
+ val myReg = RegInit(0.U(8.W))
+ val inner = Module(new InnerExample())
+ myReg := inner.myReg // ERROR
+ }
+
+ val readError = the [ChiselException] thrownBy {ChiselStage.elaborate { new OuterReadExample }}
+ val expectedReadError = """.*@: myReg in InnerExample cannot be read from module OuterReadExample."""
+ readError.getMessage should fullyMatch regex expectedReadError
+
+ val typeMismatchError = the [ChiselException] thrownBy {ChiselStage.elaborate { new RawModule {
+ val myUInt = Wire(UInt(4.W))
+ val mySInt = Wire(SInt(4.W))
+ myUInt := mySInt
+ }}}
+ val expectedTypeMismatchError = """.*@: Sink \(UInt<4>\) and Source \(SInt<4>\) have different types."""
+ typeMismatchError.getMessage should fullyMatch regex expectedTypeMismatchError
+ }
}
diff --git a/src/test/scala/chiselTests/DataPrint.scala b/src/test/scala/chiselTests/DataPrint.scala
index b5f96c4d..7fb790a8 100644
--- a/src/test/scala/chiselTests/DataPrint.scala
+++ b/src/test/scala/chiselTests/DataPrint.scala
@@ -20,6 +20,14 @@ class DataPrintSpec extends ChiselFlatSpec with Matchers {
val b = Bool()
}
+ class PartialBundleTest extends Bundle {
+ val a = UInt(8.W)
+ val b = Bool()
+ val c = SInt(8.W)
+ val e = FixedPoint(5.W, 3.BP)
+ val f = EnumTest.Type()
+ }
+
"Data types" should "have a meaningful string representation" in {
ChiselStage.elaborate { new RawModule {
UInt().toString should be ("UInt")
@@ -31,18 +39,20 @@ class DataPrintSpec extends ChiselFlatSpec with Matchers {
Vec(3, UInt(2.W)).toString should be ("UInt<2>[3]")
EnumTest.Type().toString should be ("EnumTest")
(new BundleTest).toString should be ("BundleTest")
- } }
+ new Bundle { val a = UInt(8.W) }.toString should be ("AnonymousBundle")
+ new Bundle { val a = UInt(8.W) }.a.toString should be ("UInt<8>")
+ }}
}
class BoundDataModule extends Module { // not in the test to avoid anon naming suffixes
- Wire(UInt()).toString should be("UInt(Wire in BoundDataModule)")
- Reg(SInt()).toString should be("SInt(Reg in BoundDataModule)")
+ Wire(UInt()).toString should be("BoundDataModule.?: Wire[UInt]")
+ Reg(SInt()).toString should be("BoundDataModule.?: Reg[SInt]")
val io = IO(Output(Bool())) // needs a name so elaboration doesn't fail
- io.toString should be("Bool(IO in unelaborated BoundDataModule)")
+ io.toString should be("BoundDataModule.io: IO[Bool]")
val m = Mem(4, UInt(2.W))
- m(2).toString should be("UInt<2>(MemPort in BoundDataModule)")
- (2.U + 2.U).toString should be("UInt<2>(OpResult in BoundDataModule)")
- Wire(Vec(3, UInt(2.W))).toString should be ("UInt<2>[3](Wire in BoundDataModule)")
+ m(2).toString should be("BoundDataModule.?: MemPort[UInt<2>]")
+ (2.U + 2.U).toString should be("BoundDataModule.?: OpResult[UInt<2>]")
+ Wire(Vec(3, UInt(2.W))).toString should be ("BoundDataModule.?: Wire[UInt<2>[3]]")
class InnerModule extends Module {
val io = IO(Output(new Bundle {
@@ -50,8 +60,31 @@ class DataPrintSpec extends ChiselFlatSpec with Matchers {
}))
}
val inner = Module(new InnerModule)
- inner.clock.toString should be ("Clock(IO clock in InnerModule)")
- inner.io.a.toString should be ("UInt<4>(IO io_a in InnerModule)")
+ inner.clock.toString should be ("InnerModule.clock: IO[Clock]")
+ inner.io.a.toString should be ("InnerModule.io.a: IO[UInt<4>]")
+
+ class FooTypeTest extends Bundle {
+ val foo = Vec(2, UInt(8.W))
+ val fizz = UInt(8.W)
+ }
+ val tpe = new FooTypeTest
+ val fooio: FooTypeTest = IO(Input(tpe))
+ fooio.foo(0).toString should be ("BoundDataModule.fooio.foo[0]: IO[UInt<8>]")
+
+ class NestedBundle extends Bundle {
+ val nestedFoo = UInt(8.W)
+ val nestedFooVec = Vec(2, UInt(8.W))
+ }
+ class NestedType extends Bundle {
+ val foo = new NestedBundle
+ }
+
+ val nestedTpe = new NestedType
+ val nestedio = IO(Input(nestedTpe))
+ (nestedio.foo.nestedFoo.toString should be
+ ("BoundDataModule.nestedio.foo.nestedFoo: IO[UInt<8>]"))
+ (nestedio.foo.nestedFooVec(0).toString should be
+ ("BoundDataModule.nestedio.foo.nestedFooVec[0]: IO[UInt<8>]"))
}
"Bound data types" should "have a meaningful string representation" in {
@@ -67,13 +100,12 @@ class DataPrintSpec extends ChiselFlatSpec with Matchers {
true.B.toString should be ("Bool(true)")
2.25.F(6.W, 2.BP).toString should be ("FixedPoint<6><<2>>(2.25)")
-2.25.F(6.W, 2.BP).toString should be ("FixedPoint<6><<2>>(-2.25)")
+ Vec(3, UInt(4.W)).toString should be ("UInt<4>[3]")
EnumTest.sNone.toString should be ("EnumTest(0=sNone)")
EnumTest.sTwo.toString should be ("EnumTest(2=sTwo)")
EnumTest(1.U).toString should be ("EnumTest(1=sOne)")
(new BundleTest).Lit(_.a -> 2.U, _.b -> false.B).toString should be ("BundleTest(a=UInt<8>(2), b=Bool(false))")
- new Bundle {
- val a = UInt(8.W)
- }.toString should be ("AnonymousBundle")
+ (new PartialBundleTest).Lit().toString should be ("PartialBundleTest(a=UInt<8>(DontCare), b=Bool(DontCare), c=SInt<8>(DontCare), e=FixedPoint<5><<3>>(DontCare), f=EnumTest(DontCare))")
DontCare.toString should be ("DontCare()")
} }
}
diff --git a/src/test/scala/chiselTests/FixedPointSpec.scala b/src/test/scala/chiselTests/FixedPointSpec.scala
index a1acdb17..2530bb13 100644
--- a/src/test/scala/chiselTests/FixedPointSpec.scala
+++ b/src/test/scala/chiselTests/FixedPointSpec.scala
@@ -60,6 +60,9 @@ class FixedPointFromBitsTester extends BasicTester {
val negativefp = (-3.5).F(4.BP)
val positivefp = 3.5.F(4.BP)
+ assert(- positivefp === negativefp)
+ assert(positivefp === -negativefp)
+
assert(uint2fp === uint_result)
assert(sint2fp === sint_result)
assert(fp2fp === fp_result)
diff --git a/src/test/scala/chiselTests/Harness.scala b/src/test/scala/chiselTests/Harness.scala
index 23379498..51576566 100644
--- a/src/test/scala/chiselTests/Harness.scala
+++ b/src/test/scala/chiselTests/Harness.scala
@@ -4,10 +4,7 @@ package chiselTests
import java.io.File
-import firrtl.util.BackendCompilationUtilities
-
-class HarnessSpec extends ChiselPropSpec
- with BackendCompilationUtilities {
+class HarnessSpec extends ChiselPropSpec {
def makeTrivialVerilog: (File => File) = makeHarness((prefix: String) => s"""
module ${prefix};
diff --git a/src/test/scala/chiselTests/InlineSpec.scala b/src/test/scala/chiselTests/InlineSpec.scala
index 397eac2e..59a1e984 100644
--- a/src/test/scala/chiselTests/InlineSpec.scala
+++ b/src/test/scala/chiselTests/InlineSpec.scala
@@ -5,7 +5,6 @@ package chiselTests
import chisel3._
import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage}
import chisel3.util.experimental.{InlineInstance, FlattenInstance}
-import firrtl.FirrtlExecutionSuccess
import firrtl.passes.InlineAnnotation
import firrtl.stage.{FirrtlCircuitAnnotation, FirrtlStage}
import firrtl.transforms.FlattenAnnotation
diff --git a/src/test/scala/chiselTests/IntervalSpec.scala b/src/test/scala/chiselTests/IntervalSpec.scala
index abc619e5..c223260d 100644
--- a/src/test/scala/chiselTests/IntervalSpec.scala
+++ b/src/test/scala/chiselTests/IntervalSpec.scala
@@ -15,7 +15,7 @@ import firrtl.passes.CheckTypes.InvalidConnect
import firrtl.passes.CheckWidths.{DisjointSqueeze, InvalidRange}
import firrtl.passes.{PassExceptions, WrapWithRemainder}
import firrtl.stage.{CompilerAnnotation, FirrtlCircuitAnnotation}
-import firrtl.{FIRRTLException, HighFirrtlCompiler, LowFirrtlCompiler, MiddleFirrtlCompiler, MinimumVerilogCompiler, NoneCompiler, SystemVerilogCompiler, VerilogCompiler}
+import firrtl.{HighFirrtlCompiler, LowFirrtlCompiler, MiddleFirrtlCompiler, MinimumVerilogCompiler, NoneCompiler, SystemVerilogCompiler, VerilogCompiler}
import org.scalatest.freespec.AnyFreeSpec
import org.scalatest.matchers.should.Matchers
@@ -406,6 +406,13 @@ class IntervalChainedSubTester extends BasicTester {
assert(intervalResult1 === 5.I)
assert(intervalResult2 === 5.I)
+ val negativeInterval = (-3.5).I(4.BP)
+ val positiveInterval = 3.5.I(4.BP)
+
+ assert(negativeInterval =/= positiveInterval)
+ assert(-negativeInterval === positiveInterval)
+ assert(negativeInterval === -positiveInterval)
+
stop()
}
diff --git a/src/test/scala/chiselTests/InvalidateAPISpec.scala b/src/test/scala/chiselTests/InvalidateAPISpec.scala
index b7db33cc..52ad02b4 100644
--- a/src/test/scala/chiselTests/InvalidateAPISpec.scala
+++ b/src/test/scala/chiselTests/InvalidateAPISpec.scala
@@ -105,7 +105,7 @@ class InvalidateAPISpec extends ChiselPropSpec with Matchers with BackendCompila
ChiselStage.elaborate(new ModuleWithDontCareSink)
}
}
- exception.getMessage should include("DontCare cannot be a connection sink (LHS)")
+ exception.getMessage should include("DontCare cannot be a connection sink")
}
property("a DontCare cannot be a connection sink (LHS) for <>") {
diff --git a/src/test/scala/chiselTests/LoadMemoryFromFileSpec.scala b/src/test/scala/chiselTests/LoadMemoryFromFileSpec.scala
index 8a998496..74e587bc 100644
--- a/src/test/scala/chiselTests/LoadMemoryFromFileSpec.scala
+++ b/src/test/scala/chiselTests/LoadMemoryFromFileSpec.scala
@@ -8,7 +8,6 @@ import chisel3._
import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage}
import chisel3.util.experimental.{loadMemoryFromFile,loadMemoryFromFileInline}
import chisel3.util.log2Ceil
-import firrtl.FirrtlExecutionSuccess
import firrtl.annotations.MemoryLoadFileType
import org.scalatest.freespec.AnyFreeSpec
import org.scalatest.matchers.should.Matchers
diff --git a/src/test/scala/chiselTests/Module.scala b/src/test/scala/chiselTests/Module.scala
index 7703e876..f0d6dbe7 100644
--- a/src/test/scala/chiselTests/Module.scala
+++ b/src/test/scala/chiselTests/Module.scala
@@ -9,6 +9,7 @@ import firrtl.annotations.NoTargetAnnotation
import firrtl.options.Unserializable
import scala.io.Source
+import scala.annotation.nowarn
class SimpleIO extends Bundle {
val in = Input(UInt(32.W))
@@ -167,6 +168,71 @@ class ModuleSpec extends ChiselPropSpec with Utils {
"a" -> m.a, "b" -> m.b))
})
}
+
+ property("DataMirror.modulePorts should replace deprecated <module>.getPorts") {
+ class MyModule extends Module {
+ val io = IO(new Bundle {
+ val in = Input(UInt(8.W))
+ val out = Output(Vec(2, UInt(8.W)))
+ })
+ val extra = IO(Input(UInt(8.W)))
+ val delay = RegNext(io.in)
+ io.out(0) := delay
+ io.out(1) := delay + extra
+ }
+ var mod: MyModule = null
+ ChiselStage.elaborate {
+ mod = new MyModule
+ mod
+ }
+ // Note that this is just top-level ports, Aggregates are not flattened
+ DataMirror.modulePorts(mod) should contain theSameElementsInOrderAs Seq(
+ "clock" -> mod.clock,
+ "reset" -> mod.reset,
+ "io" -> mod.io,
+ "extra" -> mod.extra
+ )
+ // Delete this when the deprecated API is deleted
+ // Note this also uses deprecated Port
+ import chisel3.internal.firrtl.Port
+ import SpecifiedDirection.{Input => IN, Unspecified}
+ mod.getPorts should contain theSameElementsInOrderAs Seq(
+ Port(mod.clock, IN),
+ Port(mod.reset, IN),
+ Port(mod.io, Unspecified),
+ Port(mod.extra, IN)
+ ): @nowarn // delete when Port and getPorts become private
+ }
+
+ property("DataMirror.fullModulePorts should return all ports including children of Aggregates") {
+ class MyModule extends Module {
+ val io = IO(new Bundle {
+ val in = Input(UInt(8.W))
+ val out = Output(Vec(2, UInt(8.W)))
+ })
+ val extra = IO(Input(UInt(8.W)))
+ val delay = RegNext(io.in)
+ io.out(0) := delay
+ io.out(1) := delay + extra
+ }
+ var mod: MyModule = null
+ ChiselStage.elaborate {
+ mod = new MyModule
+ mod
+ }
+ val expected = Seq(
+ "clock" -> mod.clock,
+ "reset" -> mod.reset,
+ "io" -> mod.io,
+ "io_out" -> mod.io.out,
+ "io_out_0" -> mod.io.out(0),
+ "io_out_1" -> mod.io.out(1),
+ "io_in" -> mod.io.in,
+ "extra" -> mod.extra
+ )
+ DataMirror.fullModulePorts(mod) should contain theSameElementsInOrderAs expected
+ }
+
property("A desiredName parameterized by a submodule should work") {
ChiselStage.elaborate(new ModuleWrapper(new ModuleWire)).name should be ("ModuleWireWrapper")
}
diff --git a/src/test/scala/chiselTests/PrintableSpec.scala b/src/test/scala/chiselTests/PrintableSpec.scala
index 25b54966..c7e819ec 100644
--- a/src/test/scala/chiselTests/PrintableSpec.scala
+++ b/src/test/scala/chiselTests/PrintableSpec.scala
@@ -3,7 +3,7 @@
package chiselTests
import chisel3._
-import chisel3.experimental.{BaseSim, ChiselAnnotation}
+import chisel3.experimental.ChiselAnnotation
import chisel3.stage.ChiselStage
import chisel3.testers.BasicTester
import firrtl.annotations.{ReferenceTarget, SingleTargetAnnotation}
@@ -23,7 +23,7 @@ object PrintfAnnotation {
/** Create annotation for a given [[printf]].
* @param c component to be annotated
*/
- def annotate(c: BaseSim): Unit = {
+ def annotate(c: VerificationStatement): Unit = {
chisel3.experimental.annotate(new ChiselAnnotation {
def toFirrtl: PrintfAnnotation = PrintfAnnotation(c.toTarget)
})
@@ -139,7 +139,6 @@ class PrintableSpec extends AnyFlatSpec with Matchers {
}
class MyBundle extends Bundle {
val foo = UInt(32.W)
- override def cloneType: this.type = (new MyBundle).asInstanceOf[this.type]
}
class MyModule extends BasicTester {
override def desiredName: String = "MyModule"
@@ -246,7 +245,7 @@ class PrintableSpec extends AnyFlatSpec with Matchers {
// check for expected annotations
exactly(3, annoLines) should include ("chiselTests.PrintfAnnotation")
exactly(1, annoLines) should include ("~PrintfAnnotationTest|PrintfAnnotationTest>farewell")
- exactly(1, annoLines) should include ("~PrintfAnnotationTest|PrintfAnnotationTest>SIM")
+ exactly(1, annoLines) should include ("~PrintfAnnotationTest|PrintfAnnotationTest>printf")
exactly(1, annoLines) should include ("~PrintfAnnotationTest|PrintfAnnotationTest>howdy")
// read in FIRRTL file
@@ -256,7 +255,7 @@ class PrintableSpec extends AnyFlatSpec with Matchers {
// check that verification components have expected names
exactly(1, firLines) should include ("""printf(clock, UInt<1>("h1"), "hello AnonymousBundle(foo -> %d, bar -> %d)", myBun.foo, myBun.bar) : howdy""")
- exactly(1, firLines) should include ("""printf(clock, UInt<1>("h1"), "goodbye AnonymousBundle(foo -> %d, bar -> %d)", myBun.foo, myBun.bar) : SIM""")
+ exactly(1, firLines) should include ("""printf(clock, UInt<1>("h1"), "goodbye AnonymousBundle(foo -> %d, bar -> %d)", myBun.foo, myBun.bar) : printf""")
exactly(1, firLines) should include ("""printf(clock, UInt<1>("h1"), "adieu AnonymousBundle(foo -> %d, bar -> %d)", myBun.foo, myBun.bar) : farewell""")
}
}
diff --git a/src/test/scala/chiselTests/QueueFlushSpec.scala b/src/test/scala/chiselTests/QueueFlushSpec.scala
index 11a411a8..9e0c6bb4 100644
--- a/src/test/scala/chiselTests/QueueFlushSpec.scala
+++ b/src/test/scala/chiselTests/QueueFlushSpec.scala
@@ -40,11 +40,11 @@ abstract class FlushQueueTesterBase(elements: Seq[Int], queueDepth: Int, bitWidt
q.io.deq.ready := LFSR(16)(tap)
q.io.enq.bits := elems(inCnt.value)
- when(q.io.enq.fire()) {
+ when(q.io.enq.fire) {
inCnt.inc()
currQCnt := currQCnt + 1.U //counts how many items have been enqueued
}
- when(q.io.deq.fire()) {
+ when(q.io.deq.fire) {
assert(flushRegister === false.B) //check queue isn't flushed (can't dequeue an empty queue)
}
when(flushRegister) { //Internal signal maybe_full is a register so some signals update on the next cycle
@@ -70,18 +70,18 @@ class QueueGetsFlushedTester(elements: Seq[Int], queueDepth: Int, bitWidth: Int,
flush := LFSR(16)((tap + 3) % 16) //testing a flush when flush is called randomly
val halfCnt = (queueDepth + 1)/2
- when(q.io.deq.fire()) {
+ when(q.io.deq.fire) {
//ensure that what comes out is what comes in
assert(currQCnt <= queueDepth.U)
assert(elems(outCnt) === q.io.deq.bits)
outCnt := outCnt + 1.U
when (currQCnt > 0.U) {
- currQCnt := Mux(q.io.enq.fire(), currQCnt, (currQCnt - 1.U))
+ currQCnt := Mux(q.io.enq.fire, currQCnt, (currQCnt - 1.U))
}
}
when(flush) {
assert(currQCnt === 0.U || q.io.deq.valid)
- outCnt := outCnt + Mux(q.io.enq.fire(), (currQCnt + 1.U), currQCnt)
+ outCnt := outCnt + Mux(q.io.enq.fire, (currQCnt + 1.U), currQCnt)
currQCnt := 0.U //resets the number of items currently inside queue
}
}
@@ -102,7 +102,7 @@ class EmptyFlushEdgecaseTester (elements: Seq[Int], queueDepth: Int, bitWidth: I
flush := (cycleCounter.value === 0.U && inCnt.value === 0.U) //flushed only before anything is enqueued
q.io.enq.valid := (inCnt.value < elements.length.U) && !flush
- when(q.io.deq.fire()) {
+ when(q.io.deq.fire) {
assert(elems(outCnt) === q.io.deq.bits)
outCnt := outCnt + 1.U
}
@@ -124,7 +124,7 @@ class EnqueueEmptyFlushEdgecaseTester (elements: Seq[Int], queueDepth: Int, bitW
flush := (cycleCounter.value === 0.U && inCnt.value === 0.U) //flushed only before anything is enqueued
cycleCounter.inc() //counts every cycle
- when(q.io.deq.fire()) {
+ when(q.io.deq.fire) {
//flush and enqueue were both active on the first cycle,
//so that element is flushed immediately which makes outCnt off by one
assert(elems(outCounter.value + 1.U) === q.io.deq.bits) //ensure that what comes out is what comes in
@@ -145,7 +145,7 @@ class FullQueueFlushEdgecaseTester (elements: Seq[Int], queueDepth: Int, bitWidt
//testing a flush when queue is full
flush := (currQCnt === queueDepth.U)
- when(q.io.deq.fire()) {
+ when(q.io.deq.fire) {
//ensure that what comes out is what comes in
assert(currQCnt <= queueDepth.U)
assert(elems(outCnt) === q.io.deq.bits)
@@ -177,7 +177,7 @@ class DequeueFullQueueEdgecaseTester (elements: Seq[Int], queueDepth: Int, bitWi
q.io.enq.valid := !flushRegister
q.io.deq.ready := flush
- when(q.io.deq.fire()) {
+ when(q.io.deq.fire) {
//ensure that what comes out is what comes in
assert(currQCnt <= queueDepth.U)
assert(elems(outCnt) === q.io.deq.bits)
@@ -191,7 +191,7 @@ class DequeueFullQueueEdgecaseTester (elements: Seq[Int], queueDepth: Int, bitWi
}
when(flushRegister) {
//check that queue gets flushed when queue is full
- assert(q.io.deq.fire() === false.B)
+ assert(q.io.deq.fire === false.B)
}
}
diff --git a/src/test/scala/chiselTests/QueueSpec.scala b/src/test/scala/chiselTests/QueueSpec.scala
index 51b899cb..9eb6c20c 100644
--- a/src/test/scala/chiselTests/QueueSpec.scala
+++ b/src/test/scala/chiselTests/QueueSpec.scala
@@ -21,10 +21,10 @@ class ThingsPassThroughTester(elements: Seq[Int], queueDepth: Int, bitWidth: Int
q.io.deq.ready := LFSR(16)(tap)
q.io.flush.foreach { _ := false.B } //Flush behavior is tested in QueueFlushSpec
q.io.enq.bits := elems(inCnt.value)
- when(q.io.enq.fire()) {
+ when(q.io.enq.fire) {
inCnt.inc()
}
- when(q.io.deq.fire()) {
+ when(q.io.deq.fire) {
//ensure that what comes out is what comes in
assert(elems(outCnt.value) === q.io.deq.bits)
outCnt.inc()
@@ -51,10 +51,10 @@ class QueueReasonableReadyValid(elements: Seq[Int], queueDepth: Int, bitWidth: I
assert(q.io.deq.valid || q.io.count === 0.U)
q.io.enq.bits := elems(inCnt.value)
- when(q.io.enq.fire()) {
+ when(q.io.enq.fire) {
inCnt.inc()
}
- when(q.io.deq.fire()) {
+ when(q.io.deq.fire) {
outCnt.inc()
}
when(outCnt.value === elements.length.U) {
@@ -74,11 +74,11 @@ class CountIsCorrectTester(elements: Seq[Int], queueDepth: Int, bitWidth: Int, t
q.io.deq.ready := LFSR(16)(tap)
q.io.enq.bits := elems(inCnt.value)
- when(q.io.enq.fire()) {
+ when(q.io.enq.fire) {
inCnt.inc()
assert(q.io.count === (inCnt.value - outCnt.value))
}
- when(q.io.deq.fire()) {
+ when(q.io.deq.fire) {
outCnt.inc()
assert(q.io.count === (inCnt.value - outCnt.value))
}
@@ -103,10 +103,10 @@ class QueueSinglePipeTester(elements: Seq[Int], bitWidth: Int, tap: Int, useSync
assert(q.io.enq.ready || (q.io.count === 1.U && !q.io.deq.ready))
q.io.enq.bits := elems(inCnt.value)
- when(q.io.enq.fire()) {
+ when(q.io.enq.fire) {
inCnt.inc()
}
- when(q.io.deq.fire()) {
+ when(q.io.deq.fire) {
outCnt.inc()
}
@@ -129,10 +129,10 @@ class QueuePipeTester(elements: Seq[Int], queueDepth: Int, bitWidth: Int, tap: I
assert(q.io.enq.ready || (q.io.count === queueDepth.U && !q.io.deq.ready))
q.io.enq.bits := elems(inCnt.value)
- when(q.io.enq.fire()) {
+ when(q.io.enq.fire) {
inCnt.inc()
}
- when(q.io.deq.fire()) {
+ when(q.io.deq.fire) {
outCnt.inc()
}
@@ -155,13 +155,13 @@ class QueueFlowTester(elements: Seq[Int], queueDepth: Int, bitWidth: Int, tap: I
q.io.deq.ready := LFSR(16)(tap)
//Queue should be empty or valid
- assert(q.io.deq.valid || (q.io.count === 0.U && !q.io.enq.fire()))
+ assert(q.io.deq.valid || (q.io.count === 0.U && !q.io.enq.fire))
q.io.enq.bits := elems(inCnt.value)
- when(q.io.enq.fire()) {
+ when(q.io.enq.fire) {
inCnt.inc()
}
- when(q.io.deq.fire()) {
+ when(q.io.deq.fire) {
outCnt.inc()
}
when(outCnt.value === elements.length.U) {
@@ -183,10 +183,10 @@ class QueueFactoryTester(elements: Seq[Int], queueDepth: Int, bitWidth: Int, tap
deq.ready := LFSR(16)(tap)
enq.bits := elems(inCnt.value)
- when(enq.fire()) {
+ when(enq.fire) {
inCnt.inc()
}
- when(deq.fire()) {
+ when(deq.fire) {
//ensure that what comes out is what comes in
assert(elems(outCnt.value) === deq.bits)
outCnt.inc()
diff --git a/src/test/scala/chiselTests/RecordSpec.scala b/src/test/scala/chiselTests/RecordSpec.scala
index c21d455c..e6986efb 100644
--- a/src/test/scala/chiselTests/RecordSpec.scala
+++ b/src/test/scala/chiselTests/RecordSpec.scala
@@ -8,11 +8,12 @@ import chisel3.testers.BasicTester
import chisel3.util.{Counter, Queue}
import chisel3.experimental.DataMirror
+import scala.collection.immutable.SeqMap
+
trait RecordSpecUtils {
class MyBundle extends Bundle {
val foo = UInt(32.W)
val bar = UInt(32.W)
- override def cloneType: this.type = (new MyBundle).asInstanceOf[this.type]
}
// Useful for constructing types from CustomBundle
// This is a def because each call to this needs to return a new instance
@@ -65,6 +66,11 @@ trait RecordSpecUtils {
}
}
+ class AliasedRecord extends Module {
+ val field = UInt(32.W)
+ val io = IO(new CustomBundle("in" -> Input(field), "out" -> Output(field)))
+ }
+
class RecordIOModule extends Module {
val io = IO(new CustomBundle("in" -> Input(UInt(32.W)), "out" -> Output(UInt(32.W))))
io("out") := io("in")
@@ -104,6 +110,23 @@ class RecordSpec extends ChiselFlatSpec with RecordSpecUtils with Utils {
ChiselStage.elaborate { new MyModule(new MyBundle, fooBarType) }
}
+ they should "not allow aliased fields" in {
+ class AliasedFieldRecord extends Record {
+ val foo = UInt(8.W)
+ val elements = SeqMap("foo" -> foo, "bar" -> foo)
+ override def cloneType: AliasedFieldRecord.this.type = this
+ }
+
+ val e = intercept[AliasedAggregateFieldException] {
+ ChiselStage.elaborate {
+ new Module {
+ val io = IO(new AliasedFieldRecord)
+ }
+ }
+ }
+ e.getMessage should include ("contains aliased fields named (bar,foo)")
+ }
+
they should "follow UInt serialization/deserialization API" in {
assertTesterPasses { new RecordSerializationTest }
}
diff --git a/src/test/scala/chiselTests/SIntOps.scala b/src/test/scala/chiselTests/SIntOps.scala
index f2e238e9..222d0ba7 100644
--- a/src/test/scala/chiselTests/SIntOps.scala
+++ b/src/test/scala/chiselTests/SIntOps.scala
@@ -44,7 +44,7 @@ class SIntOps extends Module {
io.noteqout := (a =/= b)
io.lesseqout := a <= b
io.greateqout := a >= b
- // io.negout := -a(15, 0).toSInt
+ io.negout := -a(15, 0).asSInt
io.negout := (0.S -% a)
}
diff --git a/src/test/scala/chiselTests/StrongEnum.scala b/src/test/scala/chiselTests/StrongEnum.scala
index d7dea571..404c3f66 100644
--- a/src/test/scala/chiselTests/StrongEnum.scala
+++ b/src/test/scala/chiselTests/StrongEnum.scala
@@ -257,8 +257,8 @@ class IsLitTester extends BasicTester {
for (e <- EnumExample.all) {
val wire = WireDefault(e)
- assert(e.isLit())
- assert(!wire.isLit())
+ assert(e.isLit)
+ assert(!wire.isLit)
}
stop()
}
diff --git a/src/test/scala/chiselTests/TransitNameSpec.scala b/src/test/scala/chiselTests/TransitNameSpec.scala
index b21818d6..656c6731 100644
--- a/src/test/scala/chiselTests/TransitNameSpec.scala
+++ b/src/test/scala/chiselTests/TransitNameSpec.scala
@@ -6,7 +6,6 @@ import chisel3._
import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage}
import chisel3.util.TransitName
-import firrtl.FirrtlExecutionSuccess
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
diff --git a/src/test/scala/chiselTests/UIntOps.scala b/src/test/scala/chiselTests/UIntOps.scala
index 62d00de2..bc6454b8 100644
--- a/src/test/scala/chiselTests/UIntOps.scala
+++ b/src/test/scala/chiselTests/UIntOps.scala
@@ -6,6 +6,7 @@ import chisel3._
import org.scalatest._
import chisel3.stage.ChiselStage
import chisel3.testers.BasicTester
+import chisel3.util._
import org.scalacheck.Shrink
import org.scalatest.matchers.should.Matchers
@@ -22,6 +23,8 @@ class UIntOps extends Module {
val modout = Output(UInt(32.W))
val lshiftout = Output(UInt(32.W))
val rshiftout = Output(UInt(32.W))
+ val lrotateout = Output(UInt(32.W))
+ val rrotateout = Output(UInt(32.W))
val lessout = Output(Bool())
val greatout = Output(Bool())
val eqout = Output(Bool())
@@ -30,6 +33,8 @@ class UIntOps extends Module {
val greateqout = Output(Bool())
})
+ dontTouch(io)
+
val a = io.a
val b = io.b
@@ -42,6 +47,8 @@ class UIntOps extends Module {
io.modout := a % b
io.lshiftout := (a << b(3, 0))(31, 0)
io.rshiftout := a >> b
+ io.lrotateout := a.rotateLeft(5)
+ io.rrotateout := a.rotateRight(5)
io.lessout := a < b
io.greatout := a > b
io.eqout := a === b
@@ -67,6 +74,14 @@ class UIntOpsTester(a: Long, b: Long) extends BasicTester {
assert(dut.io.modout === (a % (b max 1)).U(32.W))
assert(dut.io.lshiftout === (a << (b % 16)).U(32.W))
assert(dut.io.rshiftout === (a >> b).U(32.W))
+ assert(
+ dut.io.lrotateout === s"h${Integer.rotateLeft(a.toInt, 5).toHexString}"
+ .U(32.W)
+ )
+ assert(
+ dut.io.rrotateout === s"h${Integer.rotateRight(a.toInt, 5).toHexString}"
+ .U(32.W)
+ )
assert(dut.io.lessout === (a < b).B)
assert(dut.io.greatout === (a > b).B)
assert(dut.io.eqout === (a == b).B)
@@ -98,6 +113,65 @@ class NegativeShift(t: => Bits) extends Module {
Reg(t) >> -1
}
+class BasicRotate extends BasicTester {
+ val shiftAmount = random.LFSR(4)
+ val ctr = RegInit(0.U(4.W))
+
+
+ val rotL = 1.U(3.W).rotateLeft(shiftAmount)
+ val rotR = 1.U(3.W).rotateRight(shiftAmount)
+
+ printf("Shift amount: %d rotateLeft:%b rotateRight:%b\n", shiftAmount, rotL, rotR)
+
+ switch(shiftAmount % 3.U) {
+ is(0.U, 3.U) {
+ assert(rotL === "b001".U)
+ assert(rotR === "b001".U)
+ }
+ is(1.U) {
+ assert(rotL === "b010".U)
+ assert(rotR === "b100".U)
+ }
+ is(2.U) {
+ assert(rotL === "b100".U)
+ assert(rotR === "b010".U)
+ }
+ }
+
+ ctr := ctr + 1.U
+
+ when (ctr === 15.U){
+ stop()
+ }
+}
+
+/** rotating a w-bit word left by n should be equivalent to rotating it by w - n
+ * to the left
+ */
+class MatchedRotateLeftAndRight(w: Int = 13) extends BasicTester {
+ val initValue = BigInt(w, scala.util.Random)
+ println(s"Initial value: ${initValue.toString(2)}")
+
+ val maxWidthBits = log2Ceil(w + 1)
+ val shiftAmount1 = RegInit(0.U(w.W))
+ val shiftAmount2 = RegInit(w.U(w.W))
+ shiftAmount1 := shiftAmount1 + 1.U
+ shiftAmount2 := shiftAmount2 - 1.U
+
+ val value = RegInit(initValue.U(w.W))
+
+ val out1 = value.rotateLeft(shiftAmount1)
+ val out2 = value.rotateRight(shiftAmount2)
+
+ printf("rotateLeft by %d: %b\n", shiftAmount1, out1)
+
+ assert(out1 === out2)
+ when(shiftAmount1 === w.U) {
+ assert(out1 === initValue.U)
+ stop()
+ }
+}
+
class UIntLitExtractTester extends BasicTester {
assert("b101010".U(2) === false.B)
assert("b101010".U(3) === true.B)
@@ -140,6 +214,16 @@ class UIntOpsSpec extends ChiselPropSpec with Matchers with Utils {
}
}
+ property("rotateLeft and rotateRight should work for dynamic shift values") {
+ assertTesterPasses(new BasicRotate)
+ }
+
+ property(
+ "rotateLeft and rotateRight should be consistent for dynamic shift values"
+ ) {
+ assertTesterPasses(new MatchedRotateLeftAndRight)
+ }
+
property("Bit extraction on literals should work for all non-negative indices") {
assertTesterPasses(new UIntLitExtractTester)
}
diff --git a/src/test/scala/chiselTests/Vec.scala b/src/test/scala/chiselTests/Vec.scala
index 97aea909..24ba0bf8 100644
--- a/src/test/scala/chiselTests/Vec.scala
+++ b/src/test/scala/chiselTests/Vec.scala
@@ -313,6 +313,36 @@ class ModuleIODynamicIndexTester(n: Int) extends BasicTester {
when (done) { stop() }
}
+class ReduceTreeTester() extends BasicTester {
+ class FooIO[T <: Data](n: Int, private val gen: T) extends Bundle {
+ val in = Flipped(Vec(n, new DecoupledIO(gen)))
+ val out = new DecoupledIO(gen)
+ }
+
+ class Foo[T <: Data](n: Int, private val gen: T) extends Module {
+ val io = IO(new FooIO(n, gen))
+
+ def foo(a: DecoupledIO[T], b: DecoupledIO[T]) = {
+ a.ready := true.B
+ b.ready := true.B
+ val out = Wire(new DecoupledIO(gen))
+
+ out.valid := true.B
+
+ val regSel = RegInit(false.B)
+ out.bits := Mux(regSel, a.bits, b.bits)
+ out.ready := a.ready
+ out
+ }
+
+ io.out <> io.in.reduceTree(foo)
+ }
+
+ val dut = Module(new Foo(5, UInt(5.W)))
+ dut.io := DontCare
+ stop()
+}
+
class VecSpec extends ChiselPropSpec with Utils {
// Disable shrinking on error.
implicit val noShrinkListVal = Shrink[List[Int]](_ => Stream.empty)
@@ -456,4 +486,8 @@ class VecSpec extends ChiselPropSpec with Utils {
}}
}
}
+
+ property("reduceTree should preserve input/output type") {
+ assertTesterPasses { new ReduceTreeTester() }
+ }
}
diff --git a/src/test/scala/chiselTests/VecLiteralSpec.scala b/src/test/scala/chiselTests/VecLiteralSpec.scala
index d91cd2f4..74d8c005 100644
--- a/src/test/scala/chiselTests/VecLiteralSpec.scala
+++ b/src/test/scala/chiselTests/VecLiteralSpec.scala
@@ -142,17 +142,17 @@ class VecLiteralSpec extends ChiselFreeSpec with Utils {
"lowest of vec literal contains least significant bits and " in {
val y = Vec(4, UInt(8.W)).Lit(0 -> 0xAB.U(8.W), 1 -> 0xCD.U(8.W), 2 -> 0xEF.U(8.W), 3 -> 0xFF.U(8.W))
- y.litValue() should be(BigInt("FFEFCDAB", 16))
+ y.litValue should be(BigInt("FFEFCDAB", 16))
}
"the order lits are specified does not matter" in {
val y = Vec(4, UInt(8.W)).Lit(3 -> 0xFF.U(8.W), 2 -> 0xEF.U(8.W), 1 -> 0xCD.U(8.W), 0 -> 0xAB.U(8.W))
- y.litValue() should be(BigInt("FFEFCDAB", 16))
+ y.litValue should be(BigInt("FFEFCDAB", 16))
}
"regardless of the literals widths, packing should be done based on the width of the Vec's gen" in {
val z = Vec(4, UInt(8.W)).Lit(0 -> 0x2.U, 1 -> 0x2.U, 2 -> 0x2.U, 3 -> 0x3.U)
- z.litValue() should be(BigInt("03020202", 16))
+ z.litValue should be(BigInt("03020202", 16))
}
"packing sparse vec lits should not pack, litOption returns None" in {
@@ -221,7 +221,7 @@ class VecLiteralSpec extends ChiselFreeSpec with Utils {
chisel3.assert(outsideVecLit(2) === 0xBB.U)
chisel3.assert(outsideVecLit(3) === 0xAA.U)
- chisel3.assert(outsideVecLit.litValue().U === outsideVecLit.asUInt())
+ chisel3.assert(outsideVecLit.litValue.U === outsideVecLit.asUInt())
val insideVecLit = Vec(4, UInt(16.W)).Lit(0 -> 0xDD.U, 1 -> 0xCC.U, 2 -> 0xBB.U, 3 -> 0xAA.U)
chisel3.assert(insideVecLit(0) === 0xDD.U)
@@ -277,15 +277,15 @@ class VecLiteralSpec extends ChiselFreeSpec with Utils {
1 -> Vec(3, UInt(4.W)).Lit(0 -> 4.U, 1 -> 5.U, 2 -> 6.U)
)
- outerVec.litValue() should be (BigInt("654321", 16))
- outerVec(0).litValue() should be (BigInt("321", 16))
- outerVec(1).litValue() should be (BigInt("654", 16))
- outerVec(0)(0).litValue() should be (BigInt(1))
- outerVec(0)(1).litValue() should be (BigInt(2))
- outerVec(0)(2).litValue() should be (BigInt(3))
- outerVec(1)(0).litValue() should be (BigInt(4))
- outerVec(1)(1).litValue() should be (BigInt(5))
- outerVec(1)(2).litValue() should be (BigInt(6))
+ outerVec.litValue should be (BigInt("654321", 16))
+ outerVec(0).litValue should be (BigInt("321", 16))
+ outerVec(1).litValue should be (BigInt("654", 16))
+ outerVec(0)(0).litValue should be (BigInt(1))
+ outerVec(0)(1).litValue should be (BigInt(2))
+ outerVec(0)(2).litValue should be (BigInt(3))
+ outerVec(1)(0).litValue should be (BigInt(4))
+ outerVec(1)(1).litValue should be (BigInt(5))
+ outerVec(1)(2).litValue should be (BigInt(6))
}
"contained vecs should work" in {
@@ -473,19 +473,19 @@ class VecLiteralSpec extends ChiselFreeSpec with Utils {
0 -> (new SubBundle).Lit(_.foo -> 0xab.U, _.bar -> 0xc.U),
1 -> (new SubBundle).Lit(_.foo -> 0xde.U, _.bar -> 0xf.U)
)
- vec.litValue().toString(16) should be("defabc")
+ vec.litValue.toString(16) should be("defabc")
}
"vec literals can have bundle children assembled incrementally" in {
val bundle1 = (new SubBundle).Lit(_.foo -> 0xab.U, _.bar -> 0xc.U)
val bundle2 = (new SubBundle).Lit(_.foo -> 0xde.U, _.bar -> 0xf.U)
- bundle1.litValue().toString(16) should be("abc")
- bundle2.litValue().toString(16) should be("def")
+ bundle1.litValue.toString(16) should be("abc")
+ bundle2.litValue.toString(16) should be("def")
val vec = Vec(2, new SubBundle).Lit(0 -> bundle1, 1 -> bundle2)
- vec.litValue().toString(16) should be("defabc")
+ vec.litValue.toString(16) should be("defabc")
}
"bundles can contain vec lits" in {
@@ -495,7 +495,7 @@ class VecLiteralSpec extends ChiselFreeSpec with Utils {
val foo = Vec(3, UInt(4.W))
val bar = Vec(2, UInt(4.W))
}).Lit(_.foo -> vec1, _.bar -> vec2)
- bundle.litValue().toString(16) should be("cbaed")
+ bundle.litValue.toString(16) should be("cbaed")
}
"bundles can contain vec lits in-line" in {
@@ -506,21 +506,21 @@ class VecLiteralSpec extends ChiselFreeSpec with Utils {
_.foo -> Vec(3, UInt(4.W)).Lit(0 -> 0xa.U, 1 -> 0xb.U, 2 -> 0xc.U),
_.bar -> Vec(2, UInt(4.W)).Lit(0 -> 0xd.U, 1 -> 0xe.U)
)
- bundle.litValue().toString(16) should be("cbaed")
+ bundle.litValue.toString(16) should be("cbaed")
}
"Vec.Lit is a trivial Vec literal factory" in {
val vec = Vec.Lit(0xa.U, 0xb.U)
- vec(0).litValue() should be(0xa)
- vec(1).litValue() should be(0xb)
+ vec(0).litValue should be(0xa)
+ vec(1).litValue should be(0xb)
}
"Vec.Lit bases it's element width on the widest literal supplied" in {
val vec = Vec.Lit(0xa.U, 0xbbbb.U)
- vec(0).litValue() should be(0xa)
- vec(1).litValue() should be(0xbbbb)
+ vec(0).litValue should be(0xa)
+ vec(1).litValue should be(0xbbbb)
vec.length should be(2)
vec.getWidth should be(16 * 2)
- vec.litValue() should be(BigInt("bbbb000a", 16))
+ vec.litValue should be(BigInt("bbbb000a", 16))
}
}
diff --git a/src/test/scala/chiselTests/experimental/verification/VerificationSpec.scala b/src/test/scala/chiselTests/VerificationSpec.scala
index 1e080739..2d7144df 100644
--- a/src/test/scala/chiselTests/experimental/verification/VerificationSpec.scala
+++ b/src/test/scala/chiselTests/VerificationSpec.scala
@@ -1,15 +1,14 @@
// SPDX-License-Identifier: Apache-2.0
-package chiselTests.experimental.verification
+package chiselTests
import chisel3._
import chisel3.experimental.{ChiselAnnotation, verification => formal}
import chisel3.stage.ChiselStage
-import chiselTests.ChiselPropSpec
import firrtl.annotations.{ReferenceTarget, SingleTargetAnnotation}
+import org.scalatest.matchers.should.Matchers
import java.io.File
-import org.scalatest.matchers.should.Matchers
class SimpleTest extends Module {
val io = IO(new Bundle{
@@ -17,10 +16,10 @@ class SimpleTest extends Module {
val out = Output(UInt(8.W))
})
io.out := io.in
- formal.cover(io.in === 3.U)
+ cover(io.in === 3.U)
when (io.in === 3.U) {
- formal.assume(io.in =/= 2.U)
- formal.assert(io.out === io.in)
+ assume(io.in =/= 2.U)
+ assert(io.out === io.in)
}
}
@@ -35,7 +34,7 @@ object VerifAnnotation {
/** Create annotation for a given verification component.
* @param c component to be annotated
*/
- def annotate(c: experimental.BaseSim): Unit = {
+ def annotate(c: VerificationStatement): Unit = {
chisel3.experimental.annotate(new ChiselAnnotation {
def toFirrtl: VerifAnnotation = VerifAnnotation(c.toTarget)
})
@@ -60,8 +59,8 @@ class VerificationSpec extends ChiselPropSpec with Matchers {
assertContains(lines, "when _T_6 : @[VerificationSpec.scala")
assertContains(lines, "assume(clock, _T_4, UInt<1>(\"h1\"), \"\")")
- assertContains(lines, "when _T_9 : @[VerificationSpec.scala")
- assertContains(lines, "assert(clock, _T_7, UInt<1>(\"h1\"), \"\")")
+ assertContains(lines, "when _T_10 : @[VerificationSpec.scala")
+ assertContains(lines, "assert(clock, _T_8, UInt<1>(\"h1\"), \"\")")
}
property("annotation of verification constructs should work") {
@@ -72,9 +71,9 @@ class VerificationSpec extends ChiselPropSpec with Matchers {
val out = Output(UInt(8.W))
})
io.out := io.in
- val cov = formal.cover(io.in === 3.U)
- val assm = formal.assume(io.in =/= 2.U)
- val asst = formal.assert(io.out === io.in)
+ val cov = cover(io.in === 3.U)
+ val assm = chisel3.assume(io.in =/= 2.U)
+ val asst = chisel3.assert(io.out === io.in)
VerifAnnotation.annotate(cov)
VerifAnnotation.annotate(assm)
VerifAnnotation.annotate(asst)
@@ -93,7 +92,7 @@ class VerificationSpec extends ChiselPropSpec with Matchers {
val annoLines = scala.io.Source.fromFile(annoFile).getLines.toList
// check for expected verification annotations
- exactly(3, annoLines) should include ("chiselTests.experimental.verification.VerifAnnotation")
+ exactly(3, annoLines) should include ("chiselTests.VerifAnnotation")
exactly(1, annoLines) should include ("~AnnotationTest|AnnotationTest>asst")
exactly(1, annoLines) should include ("~AnnotationTest|AnnotationTest>assm")
exactly(1, annoLines) should include ("~AnnotationTest|AnnotationTest>cov")
@@ -106,7 +105,7 @@ class VerificationSpec extends ChiselPropSpec with Matchers {
// check that verification components have expected names
exactly(1, firLines) should include ("cover(clock, _T, UInt<1>(\"h1\"), \"\") : cov")
exactly(1, firLines) should include ("assume(clock, _T_3, UInt<1>(\"h1\"), \"\") : assm")
- exactly(1, firLines) should include ("assert(clock, _T_6, UInt<1>(\"h1\"), \"\") : asst")
+ exactly(1, firLines) should include ("assert(clock, _T_7, UInt<1>(\"h1\"), \"\") : asst")
}
property("annotation of verification constructs with suggested name should work") {
@@ -118,11 +117,11 @@ class VerificationSpec extends ChiselPropSpec with Matchers {
})
io.out := io.in
- val goodbye = formal.assert(io.in === 1.U)
+ val goodbye = chisel3.assert(io.in === 1.U)
goodbye.suggestName("hello")
VerifAnnotation.annotate(goodbye)
- VerifAnnotation.annotate(formal.assume(io.in =/= 2.U).suggestName("howdy"))
+ VerifAnnotation.annotate(chisel3.assume(io.in =/= 2.U).suggestName("howdy"))
}
// compile circuit
@@ -138,7 +137,7 @@ class VerificationSpec extends ChiselPropSpec with Matchers {
val annoLines = scala.io.Source.fromFile(annoFile).getLines.toList
// check for expected verification annotations
- exactly(2, annoLines) should include ("chiselTests.experimental.verification.VerifAnnotation")
+ exactly(2, annoLines) should include ("chiselTests.VerifAnnotation")
exactly(1, annoLines) should include ("~AnnotationRenameTest|AnnotationRenameTest>hello")
exactly(1, annoLines) should include ("~AnnotationRenameTest|AnnotationRenameTest>howdy")
@@ -149,6 +148,6 @@ class VerificationSpec extends ChiselPropSpec with Matchers {
// check that verification components have expected names
exactly(1, firLines) should include ("assert(clock, _T, UInt<1>(\"h1\"), \"\") : hello")
- exactly(1, firLines) should include ("assume(clock, _T_3, UInt<1>(\"h1\"), \"\") : howdy")
+ exactly(1, firLines) should include ("assume(clock, _T_4, UInt<1>(\"h1\"), \"\") : howdy")
}
}
diff --git a/src/test/scala/chiselTests/aop/SelectSpec.scala b/src/test/scala/chiselTests/aop/SelectSpec.scala
index e09e78c8..2b47c6b8 100644
--- a/src/test/scala/chiselTests/aop/SelectSpec.scala
+++ b/src/test/scala/chiselTests/aop/SelectSpec.scala
@@ -133,11 +133,10 @@ class SelectSpec extends ChiselFlatSpec {
{ dut: SelectTester =>
Seq(Select.Stop(
Seq(
- When(Select.ops("eq")(dut).dropRight(1).last.asInstanceOf[Bool]),
- When(dut.nreset),
- WhenNot(dut.overflow)
+ When(Select.ops("eq")(dut)(1).asInstanceOf[Bool]),
+ When(dut.overflow)
),
- 1,
+ 0,
dut.clock
))
}
diff --git a/src/test/scala/chiselTests/experimental/DataView.scala b/src/test/scala/chiselTests/experimental/DataView.scala
index d1620e88..7c5d170b 100644
--- a/src/test/scala/chiselTests/experimental/DataView.scala
+++ b/src/test/scala/chiselTests/experimental/DataView.scala
@@ -5,7 +5,9 @@ package chiselTests.experimental
import chiselTests.ChiselFlatSpec
import chisel3._
import chisel3.experimental.dataview._
+import chisel3.experimental.conversions._
import chisel3.experimental.DataMirror.internal.chiselTypeClone
+import chisel3.experimental.HWTuple2
import chisel3.stage.ChiselStage
import chisel3.util.{Decoupled, DecoupledIO}
@@ -50,69 +52,6 @@ object FlatDecoupledDataView {
implicit val view2 = view.invert(_ => new FlatDecoupled)
}
-// This should become part of Chisel in a later PR
-object Tuple2DataProduct {
- implicit def tuple2DataProduct[A : DataProduct, B : DataProduct] = new DataProduct[(A, B)] {
- def dataIterator(tup: (A, B), path: String): Iterator[(Data, String)] = {
- val dpa = implicitly[DataProduct[A]]
- val dpb = implicitly[DataProduct[B]]
- val (a, b) = tup
- dpa.dataIterator(a, s"$path._1") ++ dpb.dataIterator(b, s"$path._2")
- }
- }
-}
-
-// This should become part of Chisel in a later PR
-object HWTuple {
- import Tuple2DataProduct._
-
- class HWTuple2[A <: Data, B <: Data](val _1: A, val _2: B) extends Bundle
-
- implicit def view[T1 : DataProduct, T2 : DataProduct, V1 <: Data, V2 <: Data](
- implicit v1: DataView[T1, V1], v2: DataView[T2, V2]
- ): DataView[(T1, T2), HWTuple2[V1, V2]] =
- DataView.mapping(
- { case (a, b) => new HWTuple2(a.viewAs[V1].cloneType, b.viewAs[V2].cloneType)},
- { case ((a, b), hwt) =>
- Seq(a.viewAs[V1] -> hwt._1,
- b.viewAs[V2] -> hwt._2)
- }
- )
-
- implicit def tuple2hwtuple[T1 : DataProduct, T2 : DataProduct, V1 <: Data, V2 <: Data](
- tup: (T1, T2))(implicit v1: DataView[T1, V1], v2: DataView[T2, V2]
- ): HWTuple2[V1, V2] = tup.viewAs[HWTuple2[V1, V2]]
-}
-
-// This should become part of Chisel in a later PR
-object SeqDataProduct {
- // Should we special case Seq[Data]?
- implicit def seqDataProduct[A : DataProduct]: DataProduct[Seq[A]] = new DataProduct[Seq[A]] {
- def dataIterator(a: Seq[A], path: String): Iterator[(Data, String)] = {
- val dpa = implicitly[DataProduct[A]]
- a.iterator
- .zipWithIndex
- .flatMap { case (elt, idx) =>
- dpa.dataIterator(elt, s"$path[$idx]")
- }
- }
- }
-}
-
-object SeqToVec {
- import SeqDataProduct._
-
- // TODO this would need a better way to determine the prototype for the Vec
- implicit def seqVec[A : DataProduct, B <: Data](implicit dv: DataView[A, B]): DataView[Seq[A], Vec[B]] =
- DataView.mapping[Seq[A], Vec[B]](
- xs => Vec(xs.size, chiselTypeClone(xs.head.viewAs[B])), // xs.head is not correct in general
- { case (s, v) => s.zip(v).map { case (a, b) => a.viewAs[B] -> b } }
- )
-
- implicit def seq2Vec[A : DataProduct, B <: Data](xs: Seq[A])(implicit dv: DataView[A, B]): Vec[B] =
- xs.viewAs[Vec[B]]
-}
-
class DataViewSpec extends ChiselFlatSpec {
behavior of "DataView"
@@ -327,15 +266,14 @@ class DataViewSpec extends ChiselFlatSpec {
chirrtl should include ("z.fizz <= b.foo")
}
- // This example should be turned into a built-in feature
- it should "enable implementing \"HardwareTuple\"" in {
- import HWTuple._
-
+ it should "enable using Seq like Data" in {
class MyModule extends Module {
val a, b, c, d = IO(Input(UInt(8.W)))
val sel = IO(Input(Bool()))
val y, z = IO(Output(UInt(8.W)))
- (y, z) := Mux(sel, (a, b), (c, d))
+ // Unclear why the implicit conversion does not work in this case for Seq
+ // That being said, it's easy enough to cast via `.viewAs` with or without
+ Seq(y, z) := Mux(sel, Seq(a, b).viewAs, Seq(c, d).viewAs[Vec[UInt]])
}
// Verilog instead of CHIRRTL because the optimizations make it much prettier
val verilog = ChiselStage.emitVerilog(new MyModule)
@@ -343,25 +281,8 @@ class DataViewSpec extends ChiselFlatSpec {
verilog should include ("assign z = sel ? b : d;")
}
- it should "support nesting of tuples" in {
- import Tuple2DataProduct._
- import HWTuple._
-
- class MyModule extends Module {
- val a, b, c, d = IO(Input(UInt(8.W)))
- val w, x, y, z = IO(Output(UInt(8.W)))
- ((w, x), (y, z)) := ((a, b), (c, d))
- }
- val chirrtl = ChiselStage.emitChirrtl(new MyModule)
- chirrtl should include ("w <= a")
- chirrtl should include ("x <= b")
- chirrtl should include ("y <= c")
- chirrtl should include ("z <= d")
- }
-
// This example should be turned into a built-in feature
it should "enable viewing Seqs as Vecs" in {
- import SeqToVec._
class MyModule extends Module {
val a, b, c = IO(Input(UInt(8.W)))
@@ -376,11 +297,6 @@ class DataViewSpec extends ChiselFlatSpec {
}
it should "support recursive composition of views" in {
- import Tuple2DataProduct._
- import SeqDataProduct._
- import SeqToVec._
- import HWTuple._
-
class MyModule extends Module {
val a, b, c, d = IO(Input(UInt(8.W)))
val w, x, y, z = IO(Output(UInt(8.W)))
@@ -397,12 +313,26 @@ class DataViewSpec extends ChiselFlatSpec {
verilog should include ("assign z = d;")
}
- it should "error if you try to dynamically index a Vec view" in {
- import SeqDataProduct._
- import SeqToVec._
- import Tuple2DataProduct._
- import HWTuple._
+ it should "support dynamic indexing for Vec identity views" in {
+ class MyModule extends Module {
+ val dataIn = IO(Input(UInt(8.W)))
+ val addr = IO(Input(UInt(2.W)))
+ val dataOut = IO(Output(UInt(8.W)))
+
+ val vec = RegInit(0.U.asTypeOf(Vec(4, UInt(8.W))))
+ val view = vec.viewAs[Vec[UInt]]
+ // Dynamic indexing is more of a "generator" in Chisel3 than an individual node
+ // This style is not recommended, this is just testing the behavior
+ val selected = view(addr)
+ selected := dataIn
+ dataOut := selected
+ }
+ val chirrtl = ChiselStage.emitChirrtl(new MyModule)
+ chirrtl should include ("vec[addr] <= dataIn")
+ chirrtl should include ("dataOut <= vec[addr]")
+ }
+ it should "error if you try to dynamically index a Vec view that does not correspond to a Vec target" in {
class MyModule extends Module {
val inA, inB = IO(Input(UInt(8.W)))
val outA, outB = IO(Output(UInt(8.W)))
@@ -411,6 +341,7 @@ class DataViewSpec extends ChiselFlatSpec {
val a, b, c, d = RegInit(0.U)
// Dynamic indexing is more of a "generator" in Chisel3 than an individual node
+ // This style is not recommended, this is just testing the behavior
val selected = Seq((a, b), (c, d)).apply(idx)
selected := (inA, inB)
(outA, outB) := selected
@@ -434,7 +365,6 @@ class DataViewSpec extends ChiselFlatSpec {
}
it should "error if the mapping is non-total in the target" in {
- import Tuple2DataProduct._
implicit val dv = DataView[(UInt, UInt), UInt](_ => UInt(), _._1 -> _)
class MyModule extends Module {
val a, b = IO(Input(UInt(8.W)))
@@ -533,7 +463,6 @@ class DataViewSpec extends ChiselFlatSpec {
}
it should "NOT error if the mapping is non-total in the target" in {
- import Tuple2DataProduct._
implicit val dv = PartialDataView[(UInt, UInt), UInt](_ => UInt(), _._2 -> _)
class MyModule extends Module {
val a, b = IO(Input(UInt(8.W)))
diff --git a/src/test/scala/chiselTests/experimental/DataViewTargetSpec.scala b/src/test/scala/chiselTests/experimental/DataViewTargetSpec.scala
index 92091631..a17b0f40 100644
--- a/src/test/scala/chiselTests/experimental/DataViewTargetSpec.scala
+++ b/src/test/scala/chiselTests/experimental/DataViewTargetSpec.scala
@@ -4,8 +4,8 @@ package chiselTests.experimental
import chisel3._
import chisel3.experimental.dataview._
+import chisel3.experimental.conversions._
import chisel3.experimental.{ChiselAnnotation, annotate}
-import chisel3.stage.ChiselStage
import chiselTests.ChiselFlatSpec
object DataViewTargetSpec {
@@ -127,7 +127,6 @@ class DataViewTargetSpec extends ChiselFlatSpec {
}
it should "support annotating views that cannot be mapped to a single ReferenceTarget" in {
- import HWTuple._
class MyBundle extends Bundle {
val a, b = Input(UInt(8.W))
val c, d = Output(UInt(8.W))
diff --git a/src/test/scala/chiselTests/experimental/TraceSpec.scala b/src/test/scala/chiselTests/experimental/TraceSpec.scala
new file mode 100644
index 00000000..59548921
--- /dev/null
+++ b/src/test/scala/chiselTests/experimental/TraceSpec.scala
@@ -0,0 +1,309 @@
+// SPDX-License-Identifier: Apache-2.0
+
+package chiselTests
+
+import chisel3._
+import chisel3.experimental.ChiselEnum
+import chisel3.experimental.Trace._
+import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage, DesignAnnotation}
+import chisel3.util.experimental.InlineInstance
+import firrtl.AnnotationSeq
+import firrtl.annotations.TargetToken.{Instance, OfModule, Ref}
+import firrtl.annotations.{CompleteTarget, InstanceTarget, ReferenceTarget}
+import org.scalatest.matchers.should.Matchers
+
+class TraceSpec extends ChiselFlatSpec with Matchers {
+
+ def refTarget(topName: String, ref: String, path: Seq[(Instance, OfModule)] = Seq()) =
+ ReferenceTarget(topName, topName, path, ref, Seq())
+
+ def instTarget(topName: String, instance: String, ofModule: String, path: Seq[(Instance, OfModule)] = Seq()) =
+ InstanceTarget(topName, topName, path, instance, ofModule)
+
+ def compile(testName: String, gen: () => Module): (os.Path, AnnotationSeq) = {
+ val testDir = os.Path(createTestDirectory(testName).getAbsolutePath)
+ val annos = (new ChiselStage).execute(
+ Array("--target-dir", s"$testDir"),
+ Seq(
+ ChiselGeneratorAnnotation(gen)
+ )
+ )
+ (testDir, annos)
+ }
+
+ "TraceFromAnnotations" should "be able to get nested name." in {
+ class Bundle0 extends Bundle {
+ val a = UInt(8.W)
+ val b = Bool()
+ val c = Enum0.Type
+ }
+
+ class Bundle1 extends Bundle {
+ val a = new Bundle0
+ val b = Vec(4, Vec(4, Bool()))
+ }
+
+ class Module0 extends Module {
+ val i = IO(Input(new Bundle1))
+ val o = IO(Output(new Bundle1))
+ val r = Reg(new Bundle1)
+ o := r
+ r := i
+
+ traceName(r)
+ traceName(i)
+ traceName(o)
+ }
+
+ class Module1 extends Module {
+ val i = IO(Input(new Bundle1))
+ val m0 = Module(new Module0)
+ m0.i := i
+ m0.o := DontCare
+ }
+
+ object Enum0 extends ChiselEnum {
+ val s0, s1, s2 = Value
+ }
+
+ val (testDir, annos) = compile("TraceFromAnnotaions", () => new Module1)
+ val dut = annos.collectFirst { case DesignAnnotation(dut) => dut }.get.asInstanceOf[Module1]
+ // out of Builder.
+
+ val oneTarget = finalTarget(annos)(dut.m0.r.a.a).head
+ val ioTarget = finalTarget(annos)(dut.m0.i.b(1)(2)).head
+
+ val topName = "Module1"
+ oneTarget should be(refTarget(topName, "r_a_a", Seq(Instance("m0") -> OfModule("Module0"))))
+
+ ioTarget should be(refTarget(topName, "i_b_1_2", Seq(Instance("m0") -> OfModule("Module0"))))
+
+ // Below codes doesn't needs to be a FIRRTL Transform.
+ def generateVerilatorConfigFile(data: Seq[Data], annos: AnnotationSeq): String =
+ """`verilator_config
+ |lint_off -rule unused
+ |lint_off -rule declfilename
+ |""".stripMargin +
+ data
+ .flatMap(finalTarget(annos))
+ .toSet
+ .map { target: CompleteTarget =>
+ s"""public_flat_rd -module "${target.tokens.collectFirst { case OfModule(m) => m }.get}" -var "${target.tokens.collectFirst { case Ref(r) => r }.get}""""
+ }
+ .mkString("\n") + "\n"
+
+ def verilatorTemplate(data: Seq[Data], annos: AnnotationSeq): String = {
+ val vpiNames = data.flatMap(finalTarget(annos)).map { ct =>
+ s"""TOP.${ct.circuit}.${ct.path.map { case (Instance(i), _) => i }.mkString(".")}.${ct.tokens.collectFirst { case Ref(r) => r }.get}"""
+ }
+ s"""
+ |#include "V${topName}.h"
+ |#include "verilated_vpi.h"
+ |#include <memory>
+ |#include <verilated.h>
+ |
+ |int vpiGetInt(const char name[]) {
+ | vpiHandle vh1 = vpi_handle_by_name((PLI_BYTE8 *)name, NULL);
+ | if (!vh1)
+ | vl_fatal(__FILE__, __LINE__, "sim_main", "No handle found");
+ | s_vpi_value v;
+ | v.format = vpiIntVal;
+ | vpi_get_value(vh1, &v);
+ | return v.value.integer;
+ |}
+ |
+ |int main(int argc, char **argv) {
+ | const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
+ | contextp->commandArgs(argc, argv);
+ | const std::unique_ptr<V$topName> top{new V$topName{contextp.get(), "TOP"}};
+ | top->reset = 0;
+ | top->clock = 0;
+ | int a_b = 1;
+ | top->i_a_b = a_b;
+ | bool started = false;
+ | int ticks = 20;
+ | while (ticks--) {
+ | contextp->timeInc(1);
+ | top->clock = !top->clock;
+ | if (!top->clock) {
+ | if (contextp->time() > 1 && contextp->time() < 10) {
+ | top->reset = 1;
+ | } else {
+ | top->reset = 0;
+ | started = true;
+ | }
+ | a_b = a_b ? 0 : 1;
+ | top->i_a_b = a_b;
+ | }
+ | top->eval();
+ | VerilatedVpi::callValueCbs();
+ | if (started && !top->clock) {
+ | const int i = top->i_a_b;
+ | const int o = vpiGetInt("${vpiNames.head}");
+ | if (i == o)
+ | vl_fatal(__FILE__, __LINE__, "sim_main", "${vpiNames.head} should be the old value of Module1.i_a_b");
+ | printf("${vpiNames.head}=%d Module1.m0.o_a_b=%d\\n", i, o);
+ | }
+ | }
+ | top->final();
+ | return 0;
+ |}
+ |""".stripMargin
+ }
+
+ val config = os.temp(dir = testDir, contents = generateVerilatorConfigFile(Seq(dut.m0.o.a.b), annos))
+ val verilog = testDir / s"$topName.v"
+ val cpp = os.temp(dir = testDir, suffix = ".cpp", contents = verilatorTemplate(Seq(dut.m0.o.a.b), annos))
+ val exe = testDir / "obj_dir" / s"V$topName"
+ os.proc("verilator", "-Wall", "--cc", "--exe", "--build", "--vpi", s"$cpp", s"$verilog", s"$config").call(stdout = os.Inherit, stderr = os.Inherit, cwd = testDir)
+ assert(os.proc(s"$exe").call(stdout = os.Inherit, stderr = os.Inherit).exitCode == 0, "verilator should exit peacefully")
+ }
+
+ "TraceFromCollideBundle" should "work" in {
+ class CollideModule extends Module {
+ val a = IO(Input(Vec(2, new Bundle {
+ val b = Flipped(Bool())
+ val c = Vec(2, new Bundle {
+ val d = UInt(2.W)
+ val e = Flipped(UInt(3.W))
+ })
+ val c_1_e = UInt(4.W)
+ })))
+ val a_0_c = IO(Output(UInt(5.W)))
+ val a__0 = IO(Output(UInt(5.W)))
+ a_0_c := DontCare
+ a__0 := DontCare
+
+ traceName(a)
+ traceName(a_0_c)
+ traceName(a__0)
+ }
+
+ val (_, annos) = compile("TraceFromCollideBundle", () => new CollideModule)
+ val dut = annos.collectFirst { case DesignAnnotation(dut) => dut }.get.asInstanceOf[CollideModule]
+
+ val topName = "CollideModule"
+
+ val a0 = finalTarget(annos)(dut.a(0))
+ val a__0 = finalTarget(annos)(dut.a__0).head
+ val a__0_ref = refTarget(topName, "a__0")
+ a0.foreach(_ shouldNot be(a__0_ref))
+ a__0 should be(a__0_ref)
+
+ val a0_c = finalTarget(annos)(dut.a(0).c)
+ val a_0_c = finalTarget(annos)(dut.a_0_c).head
+ val a_0_c_ref = refTarget(topName, "a_0_c")
+ a0_c.foreach(_ shouldNot be(a_0_c_ref))
+ a_0_c should be(a_0_c_ref)
+
+ val a0_c1_e = finalTarget(annos)(dut.a(0).c(1).e).head
+ val a0_c_1_e = finalTarget(annos)(dut.a(0).c_1_e).head
+ a0_c1_e should be(refTarget(topName, "a_0_c__1_e"))
+ a0_c_1_e should be(refTarget(topName, "a_0_c_1_e"))
+ }
+
+ "Inline should work" should "work" in {
+ class Module0 extends Module {
+ val i = IO(Input(Bool()))
+ val o = IO(Output(Bool()))
+ traceName(i)
+ o := !i
+ }
+
+ class Module1 extends Module {
+ val i = IO(Input(Bool()))
+ val o = IO(Output(Bool()))
+ val m0 = Module(new Module0 with InlineInstance)
+ m0.i := i
+ o := m0.o
+ }
+
+ val (_, annos) = compile("Inline", () => new Module1)
+ val dut = annos.collectFirst { case DesignAnnotation(dut) => dut }.get.asInstanceOf[Module1]
+
+ val m0_i = finalTarget(annos)(dut.m0.i).head
+ m0_i should be(refTarget("Module1", "m0_i"))
+ }
+
+ "Constant Propagation" should "be turned off by traceName" in {
+ class Module0 extends Module {
+ val i = WireDefault(1.U)
+ val i0 = i + 1.U
+ val o = IO(Output(UInt(2.W)))
+ traceName(i0)
+ o := i0
+ }
+
+ val (_, annos) = compile("ConstantProp", () => new Module0)
+ val dut = annos.collectFirst { case DesignAnnotation(dut) => dut }.get.asInstanceOf[Module0]
+
+ val i0 = finalTarget(annos)(dut.i0).head
+ i0 should be(refTarget("Module0", "i0"))
+ }
+
+ "Nested Module" should "work" in {
+ class Io extends Bundle {
+ val i = Input(Bool())
+ val o = Output(Bool())
+ }
+
+ class Not extends Module {
+ val io = IO(new Io)
+ io.o := !io.i
+ }
+
+ class M1 extends Module {
+ val io = IO(new Io)
+ val not = Module(new Not)
+ not.io <> io
+ }
+
+ class M2 extends Module {
+ val io = IO(new Io)
+ val m1 = Module(new M1 with InlineInstance)
+ val not = Module(new Not)
+
+ m1.io.i := io.i
+ not.io.i := io.i
+
+ io.o := m1.io.o && not.io.o
+ }
+
+ class M3 extends Module {
+ val io = IO(new Io)
+ val m2 = Module(new M2)
+ io <> m2.io
+ traceName(m2.not)
+ traceName(m2.m1.not)
+ }
+
+ val (_, annos) = compile("NestedModule", () => new M3)
+ val m3 = annos.collectFirst { case DesignAnnotation(dut) => dut }.get.asInstanceOf[M3]
+
+ val m2_m1_not = finalTarget(annos)(m3.m2.m1.not).head
+ val m2_not = finalTarget(annos)(m3.m2.not).head
+
+ m2_m1_not should be(instTarget("M3", "m1_not", "Not", Seq(Instance("m2") -> OfModule("M2"))))
+ m2_not should be(instTarget("M3", "not", "Not", Seq(Instance("m2") -> OfModule("M2"))))
+ }
+
+ "All traced signal" should "generate" in {
+ class M extends Module {
+ val a = Wire(Bool())
+ val b = Wire(Vec(2, Bool()))
+ a := DontCare
+ b := DontCare
+ Seq(a, b).foreach(traceName)
+ }
+ val (_, annos) = compile("NestedModule", () => new M)
+ val dut = annos.collectFirst { case DesignAnnotation(dut) => dut }.get.asInstanceOf[M]
+ val allTargets = finalTargetMap(annos)
+ allTargets(dut.a.toAbsoluteTarget) should be (Seq(refTarget("M", "a")))
+ allTargets(dut.b.toAbsoluteTarget) should be (Seq(
+ refTarget("M", "b_0"),
+ refTarget("M", "b_1"),
+ ))
+ allTargets(dut.b(0).toAbsoluteTarget) should be (Seq(refTarget("M", "b_0")))
+ allTargets(dut.b(1).toAbsoluteTarget) should be (Seq(refTarget("M", "b_1")))
+ }
+}
diff --git a/src/test/scala/chiselTests/experimental/Tuple.scala b/src/test/scala/chiselTests/experimental/Tuple.scala
new file mode 100644
index 00000000..5f897fbc
--- /dev/null
+++ b/src/test/scala/chiselTests/experimental/Tuple.scala
@@ -0,0 +1,163 @@
+// See LICENSE for license details.
+
+package chiselTests.experimental
+
+import chiselTests.ChiselFlatSpec
+import chisel3._
+import chisel3.experimental.conversions._
+import chisel3.stage.ChiselStage
+
+class TupleSpec extends ChiselFlatSpec {
+
+ behavior of "Tuple"
+
+ it should "enable using Tuple2 like Data" in {
+ class MyModule extends Module {
+ val a, b, c, d = IO(Input(UInt(8.W)))
+ val sel = IO(Input(Bool()))
+ val y, z = IO(Output(UInt(8.W)))
+ (y, z) := Mux(sel, (a, b), (c, d))
+ }
+ // Verilog instead of CHIRRTL because the optimizations make it much prettier
+ val verilog = ChiselStage.emitVerilog(new MyModule)
+ verilog should include ("assign y = sel ? a : c;")
+ verilog should include ("assign z = sel ? b : d;")
+ }
+
+ it should "support nesting of tuples" in {
+ class MyModule extends Module {
+ val a, b, c, d = IO(Input(UInt(8.W)))
+ val w, x, y, z = IO(Output(UInt(8.W)))
+ ((w, x), (y, z)) := ((a, b), (c, d))
+ }
+ val chirrtl = ChiselStage.emitChirrtl(new MyModule)
+ chirrtl should include ("w <= a")
+ chirrtl should include ("x <= b")
+ chirrtl should include ("y <= c")
+ chirrtl should include ("z <= d")
+ }
+
+ it should "enable using Tuple3 like Data" in {
+ class MyModule extends Module {
+ val a, b, c = IO(Input(UInt(8.W)))
+ val f, g, h = IO(Input(UInt(8.W)))
+ val sel = IO(Input(Bool()))
+ val v, w, x = IO(Output(UInt(8.W)))
+ (v, w, x) := Mux(sel, (a, b, c), (f, g, h))
+ }
+ // Verilog instead of CHIRRTL because the optimizations make it much prettier
+ val verilog = ChiselStage.emitVerilog(new MyModule)
+ verilog should include ("assign v = sel ? a : f;")
+ verilog should include ("assign w = sel ? b : g;")
+ verilog should include ("assign x = sel ? c : h;")
+ }
+
+ it should "enable using Tuple4 like Data" in {
+ class MyModule extends Module {
+ val a, b, c, d = IO(Input(UInt(8.W)))
+ val f, g, h, i = IO(Input(UInt(8.W)))
+ val sel = IO(Input(Bool()))
+ val v, w, x, y = IO(Output(UInt(8.W)))
+ (v, w, x, y) := Mux(sel, (a, b, c, d), (f, g, h, i))
+ }
+ // Verilog instead of CHIRRTL because the optimizations make it much prettier
+ val verilog = ChiselStage.emitVerilog(new MyModule)
+ verilog should include ("assign v = sel ? a : f;")
+ verilog should include ("assign w = sel ? b : g;")
+ verilog should include ("assign x = sel ? c : h;")
+ verilog should include ("assign y = sel ? d : i;")
+ }
+
+ it should "enable using Tuple5 like Data" in {
+ class MyModule extends Module {
+ val a0, a1, a2, a3, a4 = IO(Input(UInt(8.W)))
+ val b0, b1, b2, b3, b4 = IO(Input(UInt(8.W)))
+ val sel = IO(Input(Bool()))
+ val z0, z1, z2, z3, z4 = IO(Output(UInt(8.W)))
+ (z0, z1, z2, z3, z4) := Mux(sel, (a0, a1, a2, a3, a4), (b0, b1, b2, b3, b4))
+ }
+ // Verilog instead of CHIRRTL because the optimizations make it much prettier
+ val verilog = ChiselStage.emitVerilog(new MyModule)
+ for (i <- 0 until 5) {
+ verilog should include(s"assign z$i = sel ? a$i : b$i;")
+ }
+ }
+
+ it should "enable using Tuple6 like Data" in {
+ class MyModule extends Module {
+ val a0, a1, a2, a3, a4, a5 = IO(Input(UInt(8.W)))
+ val b0, b1, b2, b3, b4, b5 = IO(Input(UInt(8.W)))
+ val sel = IO(Input(Bool()))
+ val z0, z1, z2, z3, z4, z5 = IO(Output(UInt(8.W)))
+ (z0, z1, z2, z3, z4, z5) := Mux(sel, (a0, a1, a2, a3, a4, a5), (b0, b1, b2, b3, b4, b5))
+ }
+ // Verilog instead of CHIRRTL because the optimizations make it much prettier
+ val verilog = ChiselStage.emitVerilog(new MyModule)
+ for (i <- 0 until 6) {
+ verilog should include(s"assign z$i = sel ? a$i : b$i;")
+ }
+ }
+
+ it should "enable using Tuple7 like Data" in {
+ class MyModule extends Module {
+ val a0, a1, a2, a3, a4, a5, a6 = IO(Input(UInt(8.W)))
+ val b0, b1, b2, b3, b4, b5, b6 = IO(Input(UInt(8.W)))
+ val sel = IO(Input(Bool()))
+ val z0, z1, z2, z3, z4, z5, z6 = IO(Output(UInt(8.W)))
+ (z0, z1, z2, z3, z4, z5, z6) := Mux(sel, (a0, a1, a2, a3, a4, a5, a6), (b0, b1, b2, b3, b4, b5, b6))
+ }
+ // Verilog instead of CHIRRTL because the optimizations make it much prettier
+ val verilog = ChiselStage.emitVerilog(new MyModule)
+ for (i <- 0 until 7) {
+ verilog should include(s"assign z$i = sel ? a$i : b$i;")
+ }
+ }
+
+ it should "enable using Tuple8 like Data" in {
+ class MyModule extends Module {
+ val a0, a1, a2, a3, a4, a5, a6, a7 = IO(Input(UInt(8.W)))
+ val b0, b1, b2, b3, b4, b5, b6, b7 = IO(Input(UInt(8.W)))
+ val sel = IO(Input(Bool()))
+ val z0, z1, z2, z3, z4, z5, z6, z7 = IO(Output(UInt(8.W)))
+ (z0, z1, z2, z3, z4, z5, z6, z7) := Mux(sel, (a0, a1, a2, a3, a4, a5, a6, a7), (b0, b1, b2, b3, b4, b5, b6, b7))
+ }
+ // Verilog instead of CHIRRTL because the optimizations make it much prettier
+ val verilog = ChiselStage.emitVerilog(new MyModule)
+ for (i <- 0 until 8) {
+ verilog should include(s"assign z$i = sel ? a$i : b$i;")
+ }
+ }
+
+ it should "enable using Tuple9 like Data" in {
+ class MyModule extends Module {
+ val a0, a1, a2, a3, a4, a5, a6, a7, a8 = IO(Input(UInt(8.W)))
+ val b0, b1, b2, b3, b4, b5, b6, b7, b8 = IO(Input(UInt(8.W)))
+ val sel = IO(Input(Bool()))
+ val z0, z1, z2, z3, z4, z5, z6, z7, z8 = IO(Output(UInt(8.W)))
+ (z0, z1, z2, z3, z4, z5, z6, z7, z8) :=
+ Mux(sel, (a0, a1, a2, a3, a4, a5, a6, a7, a8), (b0, b1, b2, b3, b4, b5, b6, b7, b8))
+ }
+ // Verilog instead of CHIRRTL because the optimizations make it much prettier
+ val verilog = ChiselStage.emitVerilog(new MyModule)
+ for (i <- 0 until 9) {
+ verilog should include(s"assign z$i = sel ? a$i : b$i;")
+ }
+ }
+
+ it should "enable using Tuple10 like Data" in {
+ class MyModule extends Module {
+ val a0, a1, a2, a3, a4, a5, a6, a7, a8, a9 = IO(Input(UInt(8.W)))
+ val b0, b1, b2, b3, b4, b5, b6, b7, b8, b9 = IO(Input(UInt(8.W)))
+ val sel = IO(Input(Bool()))
+ val z0, z1, z2, z3, z4, z5, z6, z7, z8, z9 = IO(Output(UInt(8.W)))
+ (z0, z1, z2, z3, z4, z5, z6, z7, z8, z9) :=
+ Mux(sel, (a0, a1, a2, a3, a4, a5, a6, a7, a8, a9), (b0, b1, b2, b3, b4, b5, b6, b7, b8, b9))
+ }
+ // Verilog instead of CHIRRTL because the optimizations make it much prettier
+ val verilog = ChiselStage.emitVerilog(new MyModule)
+ for (i <- 0 until 10) {
+ verilog should include(s"assign z$i = sel ? a$i : b$i;")
+ }
+ }
+
+}
diff --git a/src/test/scala/chiselTests/experimental/hierarchy/Annotations.scala b/src/test/scala/chiselTests/experimental/hierarchy/Annotations.scala
index 43111fdd..eba412f1 100644
--- a/src/test/scala/chiselTests/experimental/hierarchy/Annotations.scala
+++ b/src/test/scala/chiselTests/experimental/hierarchy/Annotations.scala
@@ -5,24 +5,20 @@ package chiselTests.experimental.hierarchy
import _root_.firrtl.annotations._
import chisel3.experimental.{annotate, BaseModule}
import chisel3.Data
-import chisel3.experimental.hierarchy.{Instance, Definition}
+import chisel3.experimental.hierarchy.{Instance, Definition, Hierarchy}
object Annotations {
case class MarkAnnotation(target: IsMember, tag: String) extends SingleTargetAnnotation[IsMember] {
def duplicate(n: IsMember): Annotation = this.copy(target = n)
}
- case class MarkChiselInstanceAnnotation[B <: BaseModule](d: Instance[B], tag: String, isAbsolute: Boolean) extends chisel3.experimental.ChiselAnnotation {
- def toFirrtl = MarkAnnotation(d.toTarget, tag)
- }
- case class MarkChiselDefinitionAnnotation[B <: BaseModule](d: Definition[B], tag: String, isAbsolute: Boolean) extends chisel3.experimental.ChiselAnnotation {
+ case class MarkChiselHierarchyAnnotation[B <: BaseModule](d: Hierarchy[B], tag: String, isAbsolute: Boolean) extends chisel3.experimental.ChiselAnnotation {
def toFirrtl = MarkAnnotation(d.toTarget, tag)
}
case class MarkChiselAnnotation(d: Data, tag: String, isAbsolute: Boolean) extends chisel3.experimental.ChiselAnnotation {
def toFirrtl = if(isAbsolute) MarkAnnotation(d.toAbsoluteTarget, tag) else MarkAnnotation(d.toTarget, tag)
}
def mark(d: Data, tag: String): Unit = annotate(MarkChiselAnnotation(d, tag, false))
- def mark[B <: BaseModule](d: Instance[B], tag: String): Unit = annotate(MarkChiselInstanceAnnotation(d, tag, false))
- def mark[B <: BaseModule](d: Definition[B], tag: String): Unit = annotate(MarkChiselDefinitionAnnotation(d, tag, false))
+ def mark[B <: BaseModule](d: Hierarchy[B], tag: String): Unit = annotate(MarkChiselHierarchyAnnotation(d, tag, true))
def amark(d: Data, tag: String): Unit = annotate(MarkChiselAnnotation(d, tag, true))
- def amark[B <: BaseModule](d: Instance[B], tag: String): Unit = annotate(MarkChiselInstanceAnnotation(d, tag, true))
+ def amark[B <: BaseModule](d: Hierarchy[B], tag: String): Unit = annotate(MarkChiselHierarchyAnnotation(d, tag, true))
}
diff --git a/src/test/scala/chiselTests/experimental/hierarchy/DefinitionSpec.scala b/src/test/scala/chiselTests/experimental/hierarchy/DefinitionSpec.scala
index 19261c36..f33f7869 100644
--- a/src/test/scala/chiselTests/experimental/hierarchy/DefinitionSpec.scala
+++ b/src/test/scala/chiselTests/experimental/hierarchy/DefinitionSpec.scala
@@ -40,6 +40,44 @@ class DefinitionSpec extends ChiselFunSpec with Utils {
val (chirrtl, _) = getFirrtlAndAnnos(new Top)
chirrtl.serialize should include ("inst i0 of HasUninferredReset")
}
+ it("0.3: module names of repeated definition should be sequential") {
+ class Top extends Module {
+ val k = Module(new AddTwoParameterized(4, (x: Int) => Seq.tabulate(x){j =>
+ val addOneDef = Definition(new AddOneParameterized(x+j))
+ val addOne = Instance(addOneDef)
+ addOne
+ }))
+ }
+ val (chirrtl, _) = getFirrtlAndAnnos(new Top)
+ chirrtl.serialize should include ("module AddOneParameterized :")
+ chirrtl.serialize should include ("module AddOneParameterized_1 :")
+ chirrtl.serialize should include ("module AddOneParameterized_2 :")
+ chirrtl.serialize should include ("module AddOneParameterized_3 :")
+ }
+ it("0.4: multiple instantiations should have sequential names") {
+ class Top extends Module {
+ val addOneDef = Definition(new AddOneParameterized(4))
+ val addOne = Instance(addOneDef)
+ val otherAddOne = Module(new AddOneParameterized(4))
+ }
+ val (chirrtl, _) = getFirrtlAndAnnos(new Top)
+ chirrtl.serialize should include ("module AddOneParameterized :")
+ chirrtl.serialize should include ("module AddOneParameterized_1 :")
+ }
+ it("0.5: nested definitions should have sequential names") {
+ class Top extends Module {
+ val k = Module(new AddTwoWithNested(4, (x: Int) => Seq.tabulate(x){j =>
+ val addOneDef = Definition(new AddOneWithNested(x+j))
+ val addOne = Instance(addOneDef)
+ addOne
+ }))
+ }
+ val (chirrtl, _) = getFirrtlAndAnnos(new Top)
+ chirrtl.serialize should include ("module AddOneWithNested :")
+ chirrtl.serialize should include ("module AddOneWithNested_1 :")
+ chirrtl.serialize should include ("module AddOneWithNested_2 :")
+ chirrtl.serialize should include ("module AddOneWithNested_3 :")
+ }
}
describe("1: Annotations on definitions in same chisel compilation") {
it("1.0: should work on a single definition, annotating the definition") {
@@ -97,7 +135,7 @@ class DefinitionSpec extends ChiselFunSpec with Utils {
mark(definition.i1, "i0.i1")
}
val (_, annos) = getFirrtlAndAnnos(new Top)
- annos should contain(MarkAnnotation("~Top|AddTwoMixedModules/i1:AddOne_2".it, "i0.i1"))
+ annos should contain(MarkAnnotation("~Top|AddTwoMixedModules/i1:AddOne_1".it, "i0.i1"))
}
// Can you define an instantiable container? I think not.
// Instead, we can test the instantiable container in a definition
@@ -258,6 +296,17 @@ class DefinitionSpec extends ChiselFunSpec with Utils {
val (_, annos) = getFirrtlAndAnnos(new Top)
annos should contain(MarkAnnotation("~Top|HasPublicConstructorArgs>x".rt, "10"))
}
+ it("3.10: should work on unimplemented vals in abstract classes/traits") {
+ class Top() extends Module {
+ val i = Definition(new ConcreteHasBlah())
+ def f(d: Definition[HasBlah]): Unit = {
+ mark(d, d.blah.toString)
+ }
+ f(i)
+ }
+ val (_, annos) = getFirrtlAndAnnos(new Top)
+ annos should contain(MarkAnnotation("~Top|ConcreteHasBlah".mt, "10"))
+ }
}
describe("4: toDefinition") {
it("4.0: should work on modules") {
@@ -311,7 +360,7 @@ class DefinitionSpec extends ChiselFunSpec with Utils {
amark(i.i1.in, "blah")
}
val (_, annos) = getFirrtlAndAnnos(new Top)
- annos should contain(MarkAnnotation("~Top|AddTwoMixedModules/i1:AddOne_2>in".rt, "blah"))
+ annos should contain(MarkAnnotation("~Top|AddTwoMixedModules/i1:AddOne_1>in".rt, "blah"))
}
it("5.3: toAbsoluteTarget on a submodule's data, in an aggregate, within a definition") {
class Top() extends Module {
@@ -319,7 +368,7 @@ class DefinitionSpec extends ChiselFunSpec with Utils {
amark(i.i1.x.head, "blah")
}
val (_, annos) = getFirrtlAndAnnos(new Top)
- annos should contain(MarkAnnotation("~Top|InstantiatesHasVec/i1:HasVec_2>x[0]".rt, "blah"))
+ annos should contain(MarkAnnotation("~Top|InstantiatesHasVec/i1:HasVec_1>x[0]".rt, "blah"))
}
}
describe("6: @instantiable traits should work as expected") {
diff --git a/src/test/scala/chiselTests/experimental/hierarchy/Examples.scala b/src/test/scala/chiselTests/experimental/hierarchy/Examples.scala
index 23b8c9c0..c0f504ff 100644
--- a/src/test/scala/chiselTests/experimental/hierarchy/Examples.scala
+++ b/src/test/scala/chiselTests/experimental/hierarchy/Examples.scala
@@ -36,6 +36,19 @@ object Examples {
out := innerWire
}
@instantiable
+ class AddOneParameterized(width: Int) extends Module {
+ @public val in = IO(Input(UInt(width.W)))
+ @public val out = IO(Output(UInt(width.W)))
+ out := in + 1.U
+ }
+ class AddOneWithNested(width: Int) extends Module {
+ @public val in = IO(Input(UInt(width.W)))
+ @public val out = IO(Output(UInt(width.W)))
+ val addOneDef = Seq.fill(3)(Definition(new AddOne))
+ out := in + 1.U
+ }
+
+ @instantiable
class AddTwo extends Module {
@public val in = IO(Input(UInt(32.W)))
@public val out = IO(Output(UInt(32.W)))
@@ -58,6 +71,33 @@ object Examples {
out := i1.out
}
@instantiable
+ class AddTwoParameterized(width: Int, makeParameterizedOnes: Int => Seq[Instance[AddOneParameterized]]) extends Module {
+ val in = IO(Input(UInt(width.W)))
+ val out = IO(Output(UInt(width.W)))
+ val addOnes = makeParameterizedOnes(width)
+ addOnes.head.in := in
+ out := addOnes.last.out
+ addOnes.zip(addOnes.tail).foreach{ case (head, tail) => tail.in := head.out}
+ }
+ @instantiable
+ class AddTwoWithNested(width: Int, makeParameterizedOnes: Int => Seq[Instance[AddOneWithNested]]) extends Module {
+ val in = IO(Input(UInt(width.W)))
+ val out = IO(Output(UInt(width.W)))
+ val addOnes = makeParameterizedOnes(width)
+ }
+
+ @instantiable
+ class AddFour extends Module {
+ @public val in = IO(Input(UInt(32.W)))
+ @public val out = IO(Output(UInt(32.W)))
+ @public val definition = Definition(new AddTwoMixedModules)
+ @public val i0 = Instance(definition)
+ @public val i1 = Instance(definition)
+ i0.in := in
+ i1.in := i0.out
+ out := i1.out
+ }
+ @instantiable
class AggregatePortModule extends Module {
@public val io = IO(new Bundle {
val in = Input(UInt(32.W))
@@ -183,4 +223,17 @@ object Examples {
@public val out = IO(Output(UInt(3.W)))
out := RegNext(in)
}
+ @instantiable
+ abstract class HasBlah() extends Module {
+ @public val blah: Int
+ }
+
+ @instantiable
+ class ConcreteHasBlah() extends HasBlah {
+ val blah = 10
+ }
+ @instantiable
+ class HasTypeParams[D <: Data](d: D) extends Module {
+ @public val blah = Wire(d)
+ }
}
diff --git a/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala b/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala
index 3866bf87..9ceb9b40 100644
--- a/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala
+++ b/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala
@@ -89,7 +89,7 @@ class InstanceSpec extends ChiselFunSpec with Utils {
mark(i0.i1, "i0.i1")
}
val (_, annos) = getFirrtlAndAnnos(new Top)
- annos should contain (MarkAnnotation("~Top|Top/i0:AddTwoMixedModules/i1:AddOne_2".it, "i0.i1"))
+ annos should contain (MarkAnnotation("~Top|Top/i0:AddTwoMixedModules/i1:AddOne_1".it, "i0.i1"))
}
it("1.5: should work on an instantiable container, annotating a wire") {
class Top extends Module {
@@ -144,6 +144,15 @@ class InstanceSpec extends ChiselFunSpec with Utils {
val (_, annos) = getFirrtlAndAnnos(new Top)
annos should contain (MarkAnnotation("~Top|AddOneWithAnnotation>innerWire".rt, "innerWire"))
}
+ it("1.11: should work on things with type parameters"){
+ class Top extends Module {
+ val definition = Definition(new HasTypeParams[UInt](UInt(3.W)))
+ val i0 = Instance(definition)
+ mark(i0.blah, "blah")
+ }
+ val (_, annos) = getFirrtlAndAnnos(new Top)
+ annos should contain (MarkAnnotation("~Top|Top/i0:HasTypeParams>blah".rt, "blah"))
+ }
}
describe("2: Annotations on designs not in the same chisel compilation") {
it("2.0: should work on an innerWire, marked in a different compilation") {
@@ -353,7 +362,7 @@ class InstanceSpec extends ChiselFunSpec with Utils {
amark(i.i1.in, "blah")
}
val (_, annos) = getFirrtlAndAnnos(new Top)
- annos should contain(MarkAnnotation("~Top|Top/i:AddTwoMixedModules/i1:AddOne_2>in".rt, "blah"))
+ annos should contain(MarkAnnotation("~Top|Top/i:AddTwoMixedModules/i1:AddOne_1>in".rt, "blah"))
}
it("5.3: toAbsoluteTarget on a submodule's data, in an aggregate, within an instance") {
class Top() extends Module {
@@ -361,7 +370,7 @@ class InstanceSpec extends ChiselFunSpec with Utils {
amark(i.i1.x.head, "blah")
}
val (_, annos) = getFirrtlAndAnnos(new Top)
- annos should contain(MarkAnnotation("~Top|Top/i:InstantiatesHasVec/i1:HasVec_2>x[0]".rt, "blah"))
+ annos should contain(MarkAnnotation("~Top|Top/i:InstantiatesHasVec/i1:HasVec_1>x[0]".rt, "blah"))
}
it("5.4: toAbsoluteTarget on a submodule's data, in an aggregate, within an instance, ILit") {
class MyBundle extends Bundle { val x = UInt(3.W) }
@@ -379,7 +388,7 @@ class InstanceSpec extends ChiselFunSpec with Utils {
amark(i.i1.x.head.x, "blah")
}
val (_, annos) = getFirrtlAndAnnos(new Top)
- annos should contain(MarkAnnotation("~Top|Top/i:InstantiatesHasVec/i1:HasVec_2>x[0].x".rt, "blah"))
+ annos should contain(MarkAnnotation("~Top|Top/i:InstantiatesHasVec/i1:HasVec_1>x[0].x".rt, "blah"))
}
it("5.5: toAbsoluteTarget on a subinstance") {
class Top() extends Module {
@@ -620,7 +629,7 @@ class InstanceSpec extends ChiselFunSpec with Utils {
}
it("7.3: should work with DataView + implicit conversion") {
- import chiselTests.experimental.SeqToVec._
+ import chisel3.experimental.conversions._
@instantiable
class MyModule extends RawModule {
private val a = IO(Input(UInt(8.W)))
@@ -705,5 +714,142 @@ class InstanceSpec extends ChiselFunSpec with Utils {
}
}
}
+ describe("9: isA[..]") {
+ it("9.0: it should work on simple classes") {
+ class Top extends Module {
+ val d = Definition(new AddOne)
+ require(d.isA[AddOne])
+ }
+ getFirrtlAndAnnos(new Top)
+ }
+ it("9.1: it should not work on inner classes") {
+ class InnerClass extends Module
+ class Top extends Module {
+ val d = Definition(new InnerClass)
+ "require(d.isA[Module])" should compile // ensures that the test below is checking something useful
+ "require(d.isA[InnerClass])" shouldNot compile
+ }
+ getFirrtlAndAnnos(new Top)
+ }
+ it("9.2: it should work on super classes") {
+ class InnerClass extends Module
+ class Top extends Module {
+ val d = Definition(new InnerClass)
+ require(d.isA[Module])
+ }
+ getFirrtlAndAnnos(new Top)
+ }
+ it("9.2: it should work after casts") {
+ class Top extends Module {
+ val d0: Definition[Module] = Definition(new AddOne)
+ require(d0.isA[AddOne])
+ val d1: Definition[Module] = Definition((new AddOne).asInstanceOf[Module])
+ require(d1.isA[AddOne])
+ val i0: Instance[Module] = Instance(d0)
+ require(i0.isA[AddOne])
+ val i1: Instance[Module] = Instance(d1)
+ require(i1.isA[AddOne])
+ val i2: Instance[Module] = Instance(Definition(new AddOne))
+ require(i2.isA[AddOne])
+ }
+ getFirrtlAndAnnos(new Top)
+ }
+ }
+ describe("10: Select APIs") {
+ it("10.0: instancesOf") {
+ val aspect = aop.inspecting.InspectingAspect({ m: AddTwoMixedModules =>
+ val targets = aop.Select.instancesOf[AddOne](m.toDefinition).map { i: Instance[AddOne] => i.toTarget }
+ targets should be (Seq(
+ "~AddTwoMixedModules|AddTwoMixedModules/i0:AddOne".it,
+ "~AddTwoMixedModules|AddTwoMixedModules/i1:AddOne_1".it,
+ ))
+ })
+ getFirrtlAndAnnos(new AddTwoMixedModules, Seq(aspect))
+ }
+ it("10.1: instancesIn") {
+ val aspect = aop.inspecting.InspectingAspect({ m: AddTwoMixedModules =>
+ val insts = aop.Select.instancesIn(m.toDefinition)
+ val abs = insts.map { i: Instance[BaseModule] => i.toAbsoluteTarget }
+ val rel = insts.map { i: Instance[BaseModule] => i.toTarget }
+ abs should be (Seq(
+ "~AddTwoMixedModules|AddTwoMixedModules/i0:AddOne".it,
+ "~AddTwoMixedModules|AddTwoMixedModules/i1:AddOne_1".it,
+ ))
+ rel should be (Seq(
+ "~AddTwoMixedModules|AddTwoMixedModules/i0:AddOne".it,
+ "~AddTwoMixedModules|AddTwoMixedModules/i1:AddOne_1".it,
+ ))
+ })
+ getFirrtlAndAnnos(new AddTwoMixedModules, Seq(aspect))
+ }
+ it("10.2: allInstancesOf") {
+ val aspect = aop.inspecting.InspectingAspect({ m: AddFour =>
+ val insts = aop.Select.allInstancesOf[AddOne](m.toDefinition)
+ val abs = insts.map { i: Instance[AddOne] => i.in.toAbsoluteTarget }
+ val rel = insts.map { i: Instance[AddOne] => i.in.toTarget }
+ rel should be (Seq(
+ "~AddFour|AddFour/i0:AddTwoMixedModules/i0:AddOne>in".rt,
+ "~AddFour|AddFour/i0:AddTwoMixedModules/i1:AddOne_1>in".rt,
+ "~AddFour|AddFour/i1:AddTwoMixedModules/i0:AddOne>in".rt,
+ "~AddFour|AddFour/i1:AddTwoMixedModules/i1:AddOne_1>in".rt,
+ ))
+ abs should be (Seq(
+ "~AddFour|AddFour/i0:AddTwoMixedModules/i0:AddOne>in".rt,
+ "~AddFour|AddFour/i0:AddTwoMixedModules/i1:AddOne_1>in".rt,
+ "~AddFour|AddFour/i1:AddTwoMixedModules/i0:AddOne>in".rt,
+ "~AddFour|AddFour/i1:AddTwoMixedModules/i1:AddOne_1>in".rt,
+ ))
+ })
+ getFirrtlAndAnnos(new AddFour, Seq(aspect))
+ }
+ it("10.3: definitionsOf") {
+ val aspect = aop.inspecting.InspectingAspect({ m: AddTwoMixedModules =>
+ val targets = aop.Select.definitionsOf[AddOne](m.toDefinition).map { i: Definition[AddOne] => i.in.toTarget }
+ targets should be (Seq(
+ "~AddTwoMixedModules|AddOne>in".rt,
+ "~AddTwoMixedModules|AddOne_1>in".rt,
+ ))
+ })
+ getFirrtlAndAnnos(new AddTwoMixedModules, Seq(aspect))
+ }
+ it("10.4: definitionsIn") {
+ val aspect = aop.inspecting.InspectingAspect({ m: AddTwoMixedModules =>
+ val targets = aop.Select.definitionsIn(m.toDefinition).map { i: Definition[BaseModule] => i.toTarget }
+ targets should be (Seq(
+ "~AddTwoMixedModules|AddOne".mt,
+ "~AddTwoMixedModules|AddOne_1".mt,
+ ))
+ })
+ getFirrtlAndAnnos(new AddTwoMixedModules, Seq(aspect))
+ }
+ it("10.5: allDefinitionsOf") {
+ val aspect = aop.inspecting.InspectingAspect({ m: AddFour =>
+ val targets = aop.Select.allDefinitionsOf[AddOne](m.toDefinition).map { i: Definition[AddOne] => i.in.toTarget }
+ targets should be (Seq(
+ "~AddFour|AddOne>in".rt,
+ "~AddFour|AddOne_1>in".rt,
+ ))
+ })
+ getFirrtlAndAnnos(new AddFour, Seq(aspect))
+ }
+ it("10.6: Select.collectDeep should fail when combined with hierarchy package") {
+ val aspect = aop.inspecting.InspectingAspect({ m: AddFour =>
+ aop.Select.collectDeep(m) { case m: AddOne => m.toTarget }
+ })
+ intercept[Exception] { getFirrtlAndAnnos(new AddFour, Seq(aspect)) }
+ }
+ it("10.7: Select.getDeep should fail when combined with hierarchy package") {
+ val aspect = aop.inspecting.InspectingAspect({ m: AddFour =>
+ aop.Select.getDeep(m) { m: BaseModule => Nil }
+ })
+ intercept[Exception] { getFirrtlAndAnnos(new AddFour, Seq(aspect)) }
+ }
+ it("10.8: Select.instances should fail when combined with hierarchy package") {
+ val aspect = aop.inspecting.InspectingAspect({ m: AddFour =>
+ aop.Select.instances(m)
+ })
+ intercept[Exception] { getFirrtlAndAnnos(new AddFour, Seq(aspect)) }
+ }
+ }
}
diff --git a/src/test/scala/chiselTests/util/BitPatSpec.scala b/src/test/scala/chiselTests/util/BitPatSpec.scala
index 0c83493f..549e8bca 100644
--- a/src/test/scala/chiselTests/util/BitPatSpec.scala
+++ b/src/test/scala/chiselTests/util/BitPatSpec.scala
@@ -24,10 +24,18 @@ class BitPatSpec extends AnyFlatSpec with Matchers {
intercept[IllegalArgumentException]{BitPat("b")}
}
- it should "contact BitPat via ##" in {
+ it should "concat BitPat via ##" in {
(BitPat.Y(4) ## BitPat.dontCare(3) ## BitPat.N(2)).toString should be (s"BitPat(1111???00)")
}
+ it should "throw when BitPat apply to a Hardware" in {
+ intercept[java.lang.IllegalArgumentException]{
+ chisel3.stage.ChiselStage.emitChirrtl(new chisel3.Module {
+ BitPat(chisel3.Reg(chisel3.Bool()))
+ })
+ }
+ }
+
it should "index and return new BitPat" in {
val b = BitPat("b1001???")
b(0) should be(BitPat.dontCare(1))
diff --git a/src/test/scala/chiselTests/util/BitSetSpec.scala b/src/test/scala/chiselTests/util/BitSetSpec.scala
new file mode 100644
index 00000000..8120cc97
--- /dev/null
+++ b/src/test/scala/chiselTests/util/BitSetSpec.scala
@@ -0,0 +1,119 @@
+package chiselTests.util
+
+import chisel3.util.experimental.BitSet
+import chisel3.util.BitPat
+import org.scalatest.flatspec.AnyFlatSpec
+import org.scalatest.matchers.should.Matchers
+
+class BitSetSpec extends AnyFlatSpec with Matchers {
+ behavior of classOf[BitSet].toString
+
+ it should "reject unequal width when constructing a BitSet" in {
+ intercept[IllegalArgumentException] {
+ BitSet.fromString(
+ """b0010
+ |b00010
+ |""".stripMargin)
+ }
+ }
+
+ it should "return empty subtraction result correctly" in {
+ val aBitPat = BitPat("b10?")
+ val bBitPat = BitPat("b1??")
+
+ aBitPat.subtract(bBitPat).isEmpty should be (true)
+ }
+
+ it should "return nonempty subtraction result correctly" in {
+ val aBitPat = BitPat("b10?")
+ val bBitPat = BitPat("b1??")
+ val cBitPat = BitPat("b11?")
+ val dBitPat = BitPat("b100")
+
+ val diffBitPat = bBitPat.subtract(aBitPat)
+ bBitPat.cover(diffBitPat) should be (true)
+ diffBitPat.equals(cBitPat) should be (true)
+
+ val largerdiffBitPat = bBitPat.subtract(dBitPat)
+ aBitPat.cover(dBitPat) should be (true)
+ largerdiffBitPat.cover(diffBitPat) should be (true)
+ }
+
+ it should "be able to handle complex subtract between BitSet" in {
+ val aBitSet = BitSet.fromString(
+ """b?01?0
+ |b11111
+ |b00000
+ |""".stripMargin)
+ val bBitSet = BitSet.fromString(
+ """b?1111
+ |b?0000
+ |""".stripMargin
+ )
+ val expected = BitPat("b?01?0")
+
+ expected.equals(aBitSet.subtract(bBitSet)) should be (true)
+ }
+
+ it should "be generated from BitPat union" in {
+ val aBitSet = BitSet.fromString(
+ """b001?0
+ |b000??""".stripMargin)
+ val aBitPat = BitPat("b000??")
+ val bBitPat = BitPat("b001?0")
+ val cBitPat = BitPat("b00000")
+ aBitPat.cover(cBitPat) should be (true)
+ aBitSet.cover(bBitPat) should be (true)
+
+ aBitSet.equals(aBitPat.union(bBitPat)) should be (true)
+ }
+
+ it should "be generated from BitPat subtraction" in {
+ val aBitSet = BitSet.fromString(
+ """b001?0
+ |b000??""".stripMargin)
+ val aBitPat = BitPat("b00???")
+ val bBitPat = BitPat("b001?1")
+
+ aBitSet.equals(aBitPat.subtract(bBitPat)) should be (true)
+ }
+
+ it should "union two BitSet together" in {
+ val aBitSet = BitSet.fromString(
+ """b001?0
+ |b001?1
+ |""".stripMargin)
+ val bBitSet = BitSet.fromString(
+ """b000??
+ |b01???
+ |""".stripMargin
+ )
+ val cBitPat = BitPat("b0????")
+ cBitPat.equals(aBitSet.union(bBitSet)) should be (true)
+ }
+
+ it should "be decoded" 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??????"
+ )
+ ), true)
+ })
+ }
+
+}
diff --git a/src/test/scala/chiselTests/util/experimental/TruthTableSpec.scala b/src/test/scala/chiselTests/util/experimental/TruthTableSpec.scala
index 743a3cd8..255effaf 100644
--- a/src/test/scala/chiselTests/util/experimental/TruthTableSpec.scala
+++ b/src/test/scala/chiselTests/util/experimental/TruthTableSpec.scala
@@ -2,8 +2,9 @@
package chiselTests.util.experimental
+import chisel3._
import chisel3.util.BitPat
-import chisel3.util.experimental.decode.TruthTable
+import chisel3.util.experimental.decode.{TruthTable, decoder}
import org.scalatest.flatspec.AnyFlatSpec
class TruthTableSpec extends AnyFlatSpec {
@@ -34,16 +35,16 @@ class TruthTableSpec extends AnyFlatSpec {
assert(table.toString contains " 0")
}
"TruthTable" should "deserialize" in {
- assert(TruthTable(str) == table)
+ assert(TruthTable.fromString(str) == table)
}
"TruthTable" should "merge same key" in {
assert(
- TruthTable(
+ TruthTable.fromString(
"""001100->??1
|001100->1??
|???
|""".stripMargin
- ) == TruthTable(
+ ) == TruthTable.fromString(
"""001100->1?1
|???
|""".stripMargin
@@ -52,7 +53,7 @@ class TruthTableSpec extends AnyFlatSpec {
}
"TruthTable" should "crash when merging 0 and 1" in {
intercept[IllegalArgumentException] {
- TruthTable(
+ TruthTable.fromString(
"""0->0
|0->1
|???
@@ -60,4 +61,24 @@ class TruthTableSpec extends AnyFlatSpec {
)
}
}
+ "TruthTable" should "be reproducible" in {
+ class Foo extends Module {
+
+ val io = IO(new Bundle{
+ val in = Input(UInt(4.W))
+ val out = Output(UInt(16.W))
+ })
+
+
+ val table = TruthTable(
+ (0 until 16).map{
+ i => BitPat(i.U(4.W)) -> BitPat((1<<i).U(16.W))
+ },
+ BitPat.dontCare(16)
+ )
+
+ io.out := decoder.qmc(io.in, table)
+ }
+ assert(chisel3.stage.ChiselStage.emitChirrtl(new Foo) == chisel3.stage.ChiselStage.emitChirrtl(new Foo))
+ }
}