summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/test.yml2
-rw-r--r--CONTRIBUTING.md3
-rw-r--r--README.md201
-rw-r--r--build.sbt37
-rw-r--r--core/src/main/scala/chisel3/Aggregate.scala5
-rw-r--r--core/src/main/scala/chisel3/Annotation.scala11
-rw-r--r--core/src/main/scala/chisel3/Bits.scala46
-rw-r--r--core/src/main/scala/chisel3/BlackBox.scala7
-rw-r--r--core/src/main/scala/chisel3/CompileOptions.scala86
-rw-r--r--core/src/main/scala/chisel3/Data.scala34
-rw-r--r--core/src/main/scala/chisel3/Module.scala34
-rw-r--r--core/src/main/scala/chisel3/Printable.scala77
-rw-r--r--core/src/main/scala/chisel3/RawModule.scala115
-rw-r--r--core/src/main/scala/chisel3/StrongEnum.scala2
-rw-r--r--core/src/main/scala/chisel3/experimental/dataview/package.scala2
-rw-r--r--core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala14
-rw-r--r--core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala36
-rw-r--r--core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala2
-rw-r--r--core/src/main/scala/chisel3/experimental/package.scala34
-rw-r--r--core/src/main/scala/chisel3/internal/BiConnect.scala70
-rw-r--r--core/src/main/scala/chisel3/internal/Builder.scala130
-rw-r--r--core/src/main/scala/chisel3/internal/Error.scala5
-rw-r--r--core/src/main/scala/chisel3/internal/MonoConnect.scala4
-rw-r--r--core/src/main/scala/chisel3/internal/firrtl/IR.scala39
-rw-r--r--core/src/main/scala/chisel3/package.scala165
-rw-r--r--docs/src/appendix/experimental-features.md15
-rw-r--r--docs/src/cookbooks/cookbook.md40
-rw-r--r--docs/src/explanations/chisel-type-vs-scala-type.md285
-rw-r--r--docs/src/explanations/data-types.md3
-rw-r--r--docs/src/explanations/explanations.md1
-rw-r--r--docs/src/explanations/interfaces-and-connections.md2
-rw-r--r--docs/src/explanations/naming.md121
-rw-r--r--macros/src/main/scala/chisel3/internal/naming/NamingAnnotations.scala4
-rw-r--r--macros/src/main/scala/chisel3/internal/sourceinfo/SourceInfoTransform.scala28
-rw-r--r--plugin/src/main/scala/chisel3/internal/plugin/BundleComponent.scala6
-rw-r--r--plugin/src/main/scala/chisel3/internal/plugin/ChiselComponent.scala47
-rw-r--r--src/main/scala/chisel3/aop/injecting/InjectingAspect.scala3
-rw-r--r--src/main/scala/chisel3/stage/ChiselAnnotations.scala16
-rw-r--r--src/main/scala/chisel3/stage/ChiselCli.scala1
-rw-r--r--src/main/scala/chisel3/stage/ChiselOptions.scala23
-rw-r--r--src/main/scala/chisel3/stage/package.scala11
-rw-r--r--src/main/scala/chisel3/stage/phases/Elaborate.scala4
-rw-r--r--src/main/scala/chisel3/util/Arbiter.scala3
-rw-r--r--src/main/scala/chisel3/util/BitPat.scala35
-rw-r--r--src/main/scala/chisel3/util/Bitwise.scala15
-rw-r--r--src/main/scala/chisel3/util/Cat.scala6
-rw-r--r--src/main/scala/chisel3/util/CircuitMath.scala2
-rw-r--r--src/main/scala/chisel3/util/Counter.scala7
-rw-r--r--src/main/scala/chisel3/util/Decoupled.scala22
-rw-r--r--src/main/scala/chisel3/util/Reg.scala37
-rw-r--r--src/main/scala/chisel3/util/TransitName.scala11
-rw-r--r--src/main/scala/chisel3/util/Valid.scala3
-rw-r--r--src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala2
-rw-r--r--src/main/scala/chisel3/util/experimental/decode/TruthTable.scala117
-rw-r--r--src/test/scala/chiselTests/AutoClonetypeSpec.scala19
-rw-r--r--src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala39
-rw-r--r--src/test/scala/chiselTests/CompileOptionsTest.scala28
-rw-r--r--src/test/scala/chiselTests/DecoupledSpec.scala91
-rw-r--r--src/test/scala/chiselTests/ExtModule.scala44
-rw-r--r--src/test/scala/chiselTests/InstanceNameSpec.scala20
-rw-r--r--src/test/scala/chiselTests/MigrateCompileOptionsSpec.scala133
-rw-r--r--src/test/scala/chiselTests/NamingAnnotationTest.scala31
-rw-r--r--src/test/scala/chiselTests/NewAnnotationsSpec.scala72
-rw-r--r--src/test/scala/chiselTests/PrintableSpec.scala207
-rw-r--r--src/test/scala/chiselTests/SIntOps.scala6
-rw-r--r--src/test/scala/chiselTests/StrongEnum.scala5
-rw-r--r--src/test/scala/chiselTests/ToTargetSpec.scala52
-rw-r--r--src/test/scala/chiselTests/UIntOps.scala6
-rw-r--r--src/test/scala/chiselTests/Vec.scala22
-rw-r--r--src/test/scala/chiselTests/VerificationSpec.scala10
-rw-r--r--src/test/scala/chiselTests/experimental/DataMirrorSpec.scala58
-rw-r--r--src/test/scala/chiselTests/experimental/DataView.scala19
-rw-r--r--src/test/scala/chiselTests/experimental/hierarchy/SeparateElaborationSpec.scala495
-rw-r--r--src/test/scala/chiselTests/naming/NamePluginSpec.scala38
-rw-r--r--src/test/scala/chiselTests/naming/PrefixSpec.scala114
-rw-r--r--src/test/scala/chiselTests/naming/ReflectiveNamingSpec.scala161
-rw-r--r--src/test/scala/chiselTests/util/experimental/TruthTableSpec.scala17
77 files changed, 3271 insertions, 447 deletions
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index c0249269..f1fa715d 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -17,7 +17,7 @@ jobs:
matrix:
system: ["ubuntu-20.04"]
jvm: ["adopt@1.8"]
- scala: ["2.13.6", "2.12.15"]
+ scala: ["2.13.6", "2.12.16"]
espresso: ["2.4"]
runs-on: ${{ matrix.system }}
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 06b5200f..8e51fa0c 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -12,5 +12,6 @@
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.
+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 once your `master` PR is merged.
+7. If your backport PR(s) get labeled with `bp-conflict`, it means they cannot be automatically be merged. You can help get them merged by openening a PR against the already-existing backport branch (will be named something like `mergify/bp/3.5.x/pr-2512`) with the necessary cleanup changes. The admins will merge your cleanup PR and remove the `bp-conflict` label if appropriate.
diff --git a/README.md b/README.md
index 746cfd8a..d7b2dfd3 100644
--- a/README.md
+++ b/README.md
@@ -2,34 +2,113 @@
---
-## Upcoming Events
+The **Constructing Hardware in a Scala Embedded Language** ([**Chisel**](https://www.chisel-lang.org)) is an open-source hardware description language (HDL) used to describe digital electronics and circuits at the register-transfer level that facilitates **advanced circuit generation and design reuse for both ASIC and FPGA digital logic designs**.
-### Chisel Dev Meeting
-Chisel/FIRRTL development meetings happen every Monday and Tuesday from 1100--1200 PT.
+Chisel adds hardware construction primitives to the [Scala](https://www.scala-lang.org) programming language, providing designers with the power of a modern programming language to write complex, parameterizable circuit generators that produce synthesizable Verilog.
+This generator methodology enables the creation of re-usable components and libraries, such as the FIFO queue and arbiters in the [Chisel Standard Library](https://www.chisel-lang.org/api/latest/#chisel3.util.package), raising the level of abstraction in design while retaining fine-grained control.
-Call-in info and meeting notes are available [here](https://docs.google.com/document/d/1BLP2DYt59DqI-FgFCcjw8Ddl4K-WU0nHmQu0sZ_wAGo/).
+For more information on the benefits of Chisel see: ["What benefits does Chisel offer over classic Hardware Description Languages?"](https://stackoverflow.com/questions/53007782/what-benefits-does-chisel-offer-over-classic-hardware-description-languages)
-### Chisel Community Conference 2021, Shanghai, China.
-CCC is an annual gathering of Chisel community enthusiasts and technical exchange workshop.
-This year with the support of the Chisel development community and RISC-V World Conference China 2021 Committee, we have brought together designers and developers with hands-on experience in Chisel from home and abroad to share cutting-edge results and experiences from both the open source community as well as industry.
-English translated recordings version will be updated soon.
-Looking forward to CCC 2022! See you then!
+Chisel is powered by [FIRRTL (Flexible Intermediate Representation for RTL)](https://github.com/chipsalliance/firrtl), a hardware compiler framework that performs optimizations of Chisel-generated circuits and supports custom user-defined circuit transformations.
+
+* [What does Chisel code look like?](#what-does-chisel-code-look-like)
+ * [LED blink](#led-blink)
+ * [FIR Filter](#fir-filter)
+* [Getting Started](#getting-started)
+ * [Bootcamp Interactive Tutorial](#bootcamp-interactive-tutorial)
+ * [A Textbook on Chisel](#a-textbook-on-chisel)
+ * [Build Your Own Chisel Projects](#build-your-own-chisel-projects)
+ * [Guide For New Contributors](#guide-for-new-contributors)
+ * [Design Verification](#design-verification)
+* [Documentation](#documentation)
+ * [Useful Resources](#useful-resources)
+ * [Chisel Dev Meeting](#chisel-dev-meeting)
+ * [Data Types Overview](#data-types-overview)
+* [Contributor Documentation](#contributor-documentation)
+ * [Useful Resources for Contributors](#useful-resources-for-contributors)
+ * [Compiling and Testing Chisel](#compiling-and-testing-chisel)
+ * [Running Projects Against Local Chisel](#running-projects-against-local-chisel)
+ * [Building Chisel with FIRRTL in the same SBT Project](#building-chisel-with-firrtl-in-the-same-sbt-project)
+ * [Chisel3 Architecture Overview](#chisel3-architecture-overview)
+ * [Chisel Sub-Projects](#chisel-sub-projects)
+ * [Which version should I use?](#which-version-should-i-use)
---
[![Join the chat at https://gitter.im/freechipsproject/chisel3](https://badges.gitter.im/chipsalliance/chisel3.svg)](https://gitter.im/freechipsproject/chisel3?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
![CI](https://github.com/chipsalliance/chisel3/actions/workflows/test.yml/badge.svg)
[![GitHub tag (latest SemVer)](https://img.shields.io/github/v/tag/chipsalliance/chisel3.svg?include_prereleases&sort=semver)](https://github.com/chipsalliance/chisel3/releases/latest)
+[![Scala version support](https://index.scala-lang.org/chipsalliance/chisel3/chisel3/latest-by-scala-version.svg?color=blue)](https://index.scala-lang.org/chipsalliance/chisel3/chisel3)
+[![Sonatype Snapshots](https://img.shields.io/nexus/s/edu.berkeley.cs/chisel3_2.13?server=https%3A%2F%2Foss.sonatype.org)](https://oss.sonatype.org/content/repositories/snapshots/edu/berkeley/cs/)
+[![Scaladoc](https://www.javadoc.io/badge/edu.berkeley.cs/chisel3_2.13.svg?color=blue&label=Scaladoc)](https://javadoc.io/doc/edu.berkeley.cs/chisel3_2.13/latest)
-[**Chisel**](https://www.chisel-lang.org) is a hardware design language that facilitates **advanced circuit generation and design reuse for both ASIC and FPGA digital logic designs**.
-Chisel adds hardware construction primitives to the [Scala](https://www.scala-lang.org) programming language, providing designers with the power of a modern programming language to write complex, parameterizable circuit generators that produce synthesizable Verilog.
-This generator methodology enables the creation of re-usable components and libraries, such as the FIFO queue and arbiters in the [Chisel Standard Library](https://www.chisel-lang.org/api/latest/#chisel3.util.package), raising the level of abstraction in design while retaining fine-grained control.
+## What does Chisel code look like?
-For more information on the benefits of Chisel see: ["What benefits does Chisel offer over classic Hardware Description Languages?"](https://stackoverflow.com/questions/53007782/what-benefits-does-chisel-offer-over-classic-hardware-description-languages)
+### LED blink
-Chisel is powered by [FIRRTL (Flexible Intermediate Representation for RTL)](https://github.com/chipsalliance/firrtl), a hardware compiler framework that performs optimizations of Chisel-generated circuits and supports custom user-defined circuit transformations.
+```scala
+import chisel3._
+import chisel3.util._
-## What does Chisel code look like?
+class Blinky(freq: Int, startOn: Boolean = false) extends Module {
+ val io = IO(new Bundle {
+ val led0 = Output(Bool())
+ })
+ // Blink LED every second using Chisel built-in util.Counter
+ val led = RegInit(startOn.B)
+ val (_, counterWrap) = Counter(true.B, freq / 2)
+ when(counterWrap) {
+ led := ~led
+ }
+ io.led0 := led
+}
+object Main extends App {
+ // These lines generate the Verilog output
+ println(
+ new (chisel3.stage.ChiselStage).emitVerilog(
+ new Blinky(1000),
+ Array(
+ "--emission-options=disableMemRandomization,disableRegisterRandomization"
+ )
+ )
+ )
+}
+```
+
+Should output the following Verilog:
+<details>
+<summary>Click to expand!</summary>
+
+<pre class="hljs"><code><div><span class="hljs-keyword">module</span> Blinky(
+ <span class="hljs-keyword">input</span> clock,
+ <span class="hljs-keyword">input</span> reset,
+ <span class="hljs-keyword">output</span> io_led0
+);
+ <span class="hljs-keyword">reg</span> led; <span class="hljs-comment">// @[main.scala 11:20]</span>
+ <span class="hljs-keyword">reg</span> [<span class="hljs-number">8</span>:<span class="hljs-number">0</span>] counterWrap_value; <span class="hljs-comment">// @[Counter.scala 62:40]</span>
+ <span class="hljs-keyword">wire</span> counterWrap_wrap_wrap = counterWrap_value == <span class="hljs-number">9'h1f3</span>; <span class="hljs-comment">// @[Counter.scala 74:24]</span>
+ <span class="hljs-keyword">wire</span> [<span class="hljs-number">8</span>:<span class="hljs-number">0</span>] <span class="hljs-number">_</span>counterWrap_wrap_value_T_1 = counterWrap_value + <span class="hljs-number">9'h1</span>; <span class="hljs-comment">// @[Counter.scala 78:24]</span>
+ <span class="hljs-keyword">assign</span> io_led0 = led; <span class="hljs-comment">// @[main.scala 16:11]</span>
+ <span class="hljs-keyword">always</span> @(<span class="hljs-keyword">posedge</span> clock) <span class="hljs-keyword">begin</span>
+ <span class="hljs-keyword">if</span> (reset) <span class="hljs-keyword">begin</span> <span class="hljs-comment">// @[main.scala 11:20]</span>
+ led &lt;= <span class="hljs-number">1'h0</span>; <span class="hljs-comment">// @[main.scala 11:20]</span>
+ <span class="hljs-keyword">end</span> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (counterWrap_wrap_wrap) <span class="hljs-keyword">begin</span> <span class="hljs-comment">// @[main.scala 13:21]</span>
+ led &lt;= ~led; <span class="hljs-comment">// @[main.scala 14:9]</span>
+ <span class="hljs-keyword">end</span>
+ <span class="hljs-keyword">if</span> (reset) <span class="hljs-keyword">begin</span> <span class="hljs-comment">// @[Counter.scala 62:40]</span>
+ counterWrap_value &lt;= <span class="hljs-number">9'h0</span>; <span class="hljs-comment">// @[Counter.scala 62:40]</span>
+ <span class="hljs-keyword">end</span> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (counterWrap_wrap_wrap) <span class="hljs-keyword">begin</span> <span class="hljs-comment">// @[Counter.scala 88:20]</span>
+ counterWrap_value &lt;= <span class="hljs-number">9'h0</span>; <span class="hljs-comment">// @[Counter.scala 88:28]</span>
+ <span class="hljs-keyword">end</span> <span class="hljs-keyword">else</span> <span class="hljs-keyword">begin</span>
+ counterWrap_value &lt;= <span class="hljs-number">_</span>counterWrap_wrap_value_T_1; <span class="hljs-comment">// @[Counter.scala 78:15]</span>
+ <span class="hljs-keyword">end</span>
+ <span class="hljs-keyword">end</span>
+<span class="hljs-keyword">endmodule</span>
+</div></code></pre>
+
+</details>
+
+### FIR Filter
Consider an FIR filter that implements a convolution operation, as depicted in this block diagram:
@@ -53,6 +132,7 @@ class MovingSum3(bitWidth: Int) extends Module {
```
the power of Chisel comes from the ability to create generators, such as an FIR filter that is defined by the list of coefficients:
+
```scala
// Generalized FIR filter parameterized by the convolution coefficients
class FirFilter(bitWidth: Int, coeffs: Seq[UInt]) extends Module {
@@ -76,6 +156,7 @@ class FirFilter(bitWidth: Int, coeffs: Seq[UInt]) extends Module {
```
and use and re-use them across designs:
+
```scala
val movingSum3Filter = Module(new FirFilter(8, Seq(1.U, 1.U, 1.U))) // same 3-point moving sum filter as before
val delayFilter = Module(new FirFilter(8, Seq(0.U, 1.U))) // 1-cycle delay as a FIR filter
@@ -83,6 +164,7 @@ val triangleFilter = Module(new FirFilter(8, Seq(1.U, 2.U, 3.U, 2.U, 1.U))) //
```
The above can be converted to Verilog using `ChiselStage`:
+
```scala
import chisel3.stage.{ChiselStage, ChiselGeneratorAnnotation}
@@ -92,6 +174,7 @@ import chisel3.stage.{ChiselStage, ChiselGeneratorAnnotation}
```
Alternatively, you may generate some Verilog directly for inspection:
+
```scala
val verilogString = chisel3.emitVerilog(new FirFilter(8, Seq(0.U, 1.U)))
println(verilogString)
@@ -100,6 +183,7 @@ println(verilogString)
## Getting Started
### Bootcamp Interactive Tutorial
+
The [**online Chisel Bootcamp**](https://mybinder.org/v2/gh/freechipsproject/chisel-bootcamp/master) is the recommended way to get started with and learn Chisel.
**No setup is required** (it runs in the browser), nor does it assume any prior knowledge of Scala.
@@ -118,50 +202,60 @@ Follow the [chisel-template README](https://github.com/freechipsproject/chisel-t
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
// build.sbt
-scalaVersion := "2.13.7"
-addCompilerPlugin("edu.berkeley.cs" % "chisel3-plugin" % "3.5.0" cross CrossVersion.full)
-libraryDependencies += "edu.berkeley.cs" %% "chisel3" % "3.5.0"
-// We also recommend using chiseltest for writing unit tests
-libraryDependencies += "edu.berkeley.cs" %% "chiseltest" % "0.5.0" % "test"
+scalaVersion := "2.13.8"
+addCompilerPlugin("edu.berkeley.cs" % "chisel3-plugin" % "3.5.3" cross CrossVersion.full)
+libraryDependencies += "edu.berkeley.cs" %% "chisel3" % "3.5.3"
+// We also recommend using chiseltest for writing unit tests
+libraryDependencies += "edu.berkeley.cs" %% "chiseltest" % "0.5.3" % "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)
+
+If you are trying to make a contribution to this project, please read [CONTRIBUTING.md](https://github.com/chipsalliance/chisel3/blob/master/CONTRIBUTING.md)
### Design Verification
These simulation-based verification tools are available for Chisel:
-- [**iotesters**](https://github.com/freechipsproject/chisel-testers), specifically [PeekPokeTester](https://github.com/freechipsproject/chisel-testers/wiki/Using%20the%20PeekPokeTester), provides constructs (`peek`, `poke`, `expect`) similar to a non-synthesizable Verilog testbench.
-- [**testers2**](https://github.com/ucb-bar/chisel-testers2) is an in-development replacement for PeekPokeTester, providing the same base constructs but with a streamlined interface and concurrency support with `fork` and `join`.
+* [**chiseltest**](https://github.com/ucb-bar/chiseltest) is the batteries-included testing and formal verification library for Chisel-based RTL designs and a replacement for the former PeekPokeTester, providing the same base constructs but with a streamlined interface and concurrency support with `fork` and `join` with internal and Verilator integration for simulations.
## Documentation
### Useful Resources
-- [**Cheat Sheet**](https://github.com/freechipsproject/chisel-cheatsheet/releases/latest/download/chisel_cheatsheet.pdf), a 2-page reference of the base Chisel syntax and libraries
-- [**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)**](https://scastie.scala-lang.org/9ga9i2DvQymKlA5JjS1ieA)
-- [**asic-world**](http://www.asic-world.com/verilog/veritut.html) If you aren't familiar with verilog, this is a good tutorial.
+* [**Cheat Sheet**](https://github.com/freechipsproject/chisel-cheatsheet/releases/latest/download/chisel_cheatsheet.pdf), a 2-page reference of the base Chisel syntax and libraries
+* [**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.3)**](https://scastie.scala-lang.org/O3LqeVH7SWyIxD7bZRH8hA)
+* [**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).
+### Chisel Dev Meeting
+
+Chisel/FIRRTL development meetings happen every Monday and Tuesday from 1100--1200 PT.
+
+Call-in info and meeting notes are available [here](https://docs.google.com/document/d/1BLP2DYt59DqI-FgFCcjw8Ddl4K-WU0nHmQu0sZ_wAGo/).
+
### Data Types Overview
+
These are the base data types for defining circuit components:
![Image](https://raw.githubusercontent.com/chipsalliance/chisel3/master/docs/src/images/type_hierarchy.svg?sanitize=true)
## Contributor Documentation
+
This section describes how to get started contributing to Chisel itself, including how to test your version locally against other projects that pull in Chisel using [sbt's managed dependencies](https://www.scala-sbt.org/1.x/docs/Library-Dependencies.html).
### Useful Resources for Contributors
The [Useful Resources](#useful-resources) for users are also helpful for contributors.
-- [**Chisel Breakdown Slides**](https://docs.google.com/presentation/d/114YihixFBPCfUnv1inqAL8UjsiWfcNWdPHX7SeqlRQc), an introductory talk about Chisel's internals
+* [**Chisel Breakdown Slides**](https://docs.google.com/presentation/d/114YihixFBPCfUnv1inqAL8UjsiWfcNWdPHX7SeqlRQc), an introductory talk about Chisel's internals
### Compiling and Testing Chisel
@@ -184,7 +278,7 @@ Check that each is installed on your `PATH` by running `which verilator` and so
If the compilation succeeded and the dependencies noted above are installed, you can then run the included unit tests by invoking:
-```
+```bash
sbt test
```
@@ -194,13 +288,13 @@ To use the development version of Chisel (`master` branch), you will need to bui
The repository version can be found in the [build.sbt](build.sbt) file.
As of the time of writing it was:
-```
+```scala
version := "3.5-SNAPSHOT"
```
To publish your version of Chisel to the local Ivy (sbt's dependency manager) repository, run:
-```
+```bash
sbt publishLocal
```
@@ -209,7 +303,7 @@ If you need to un-publish your local copy of Chisel, remove the directory genera
In order to have your projects use this version of Chisel, you should update the `libraryDependencies` setting in your project's build.sbt file to:
-```
+```scala
libraryDependencies += "edu.berkeley.cs" %% "chisel3" % "3.5-SNAPSHOT"
```
@@ -217,16 +311,19 @@ libraryDependencies += "edu.berkeley.cs" %% "chisel3" % "3.5-SNAPSHOT"
While we recommend using the library dependency approach as described above, it is possible to build Chisel and FIRRTL in a single SBT project.
-**Caveats**
+**Caveats**:
+
* This only works for the "main" configuration; you cannot build the Chisel tests this way because `treadle` is only supported as a library dependency.
* Do not `publishLocal` when building this way. The published artifact will be missing the FIRRTL dependency.
This works by using [sbt-sriracha](http://eed3si9n.com/hot-source-dependencies-using-sbt-sriracha), an SBT plugin for toggling between source and library dependencies.
It provides two JVM system properties that, when set, will tell SBT to include FIRRTL as a source project:
+
* `sbt.sourcemode` - when set to true, SBT will look for FIRRTL in the workspace
* `sbt.workspace` - sets the root directory of the workspace
Example use:
+
```bash
# From root of this repo
git clone git@github.com:chipsalliance/firrtl.git
@@ -240,34 +337,24 @@ As an example, see [Rocket Chip](https://github.com/chipsalliance/rocket-chip)
The Chisel3 compiler consists of these main parts:
-- **The frontend**, `chisel3.*`, which is the publicly visible "API" of Chisel
- and what is used in Chisel RTL. These just add data to the...
-- **The Builder**, `chisel3.internal.Builder`, which maintains global state
- (like the currently open Module) and contains commands, generating...
-- **The intermediate data structures**, `chisel3.firrtl.*`, which are
- syntactically very similar to Firrtl. Once the entire circuit has been
- elaborated, the top-level object (a `Circuit`) is then passed to...
-- **The Firrtl emitter**, `chisel3.firrtl.Emitter`, which turns the
- intermediate data structures into a string that can be written out into a
- Firrtl file for further processing.
+* **The frontend**, `chisel3.*`, which is the publicly visible "API" of Chisel and what is used in Chisel RTL. These just add data to the...
+* **The Builder**, `chisel3.internal.Builder`, which maintains global state (like the currently open Module) and contains commands, generating...
+* **The intermediate data structures**, `chisel3.firrtl.*`, which are syntactically very similar to Firrtl. Once the entire circuit has been elaborated, the top-level object (a `Circuit`) is then passed to...
+* **The Firrtl emitter**, `chisel3.firrtl.Emitter`, which turns the intermediate data structures into a string that can be written out into a Firrtl file for further processing.
Also included is:
-- **The standard library** of circuit generators, `chisel3.util.*`. These
- contain commonly used interfaces and constructors (like `Decoupled`, which
- wraps a signal with a ready-valid pair) as well as fully parameterizable
- circuit generators (like arbiters and multiplexors).
-- **Chisel Stage**, `chisel3.stage.*`, which contains compilation and test
- functions that are invoked in the standard Verilog generation and simulation
- testing infrastructure. These can also be used as part of custom flows.
-
+
+* **The standard library** of circuit generators, `chisel3.util.*`. These contain commonly used interfaces and constructors (like `Decoupled`, which wraps a signal with a ready-valid pair) as well as fully parameterizable circuit generators (like arbiters and multiplexors).
+* **Chisel Stage**, `chisel3.stage.*`, which contains compilation and test functions that are invoked in the standard Verilog generation and simulation testing infrastructure. These can also be used as part of custom flows.
+
### Chisel Sub-Projects
Chisel consists of 4 Scala projects; each is its own separate compilation unit:
-- [`core`](core) is the bulk of the source code of Chisel, depends on `macros`
-- [`src/main`](src/main) is the "main" that brings it all together and includes a [`util`](src/main/scala/chisel3/util) library, which depends on `core`
-- [`plugin`](plugin) is the compiler plugin, no internal dependencies
-- [`macros`](macros) is most of the macros used in Chisel, no internal dependencies
+* [`core`](core) is the bulk of the source code of Chisel, depends on `macros`
+* [`src/main`](src/main) is the "main" that brings it all together and includes a [`util`](src/main/scala/chisel3/util) library, which depends on `core`
+* [`plugin`](plugin) is the compiler plugin, no internal dependencies
+* [`macros`](macros) is most of the macros used in Chisel, no internal dependencies
Code that touches lots of APIs that are private to the `chisel3` package should belong in `core`, while code that is pure Chisel should belong in `src/main`.
diff --git a/build.sbt b/build.sbt
index cc2e7d05..2d43d705 100644
--- a/build.sbt
+++ b/build.sbt
@@ -18,8 +18,8 @@ lazy val commonSettings = Seq (
organization := "edu.berkeley.cs",
version := "3.5.4",
autoAPIMappings := true,
- scalaVersion := "2.12.15",
- crossScalaVersions := Seq("2.13.6", "2.12.15"),
+ scalaVersion := "2.12.16",
+ crossScalaVersions := Seq("2.13.6", "2.12.16"),
scalacOptions := Seq("-deprecation", "-feature"),
libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value,
// Macros paradise is integrated into 2.13 but requires a scalacOption
@@ -109,6 +109,7 @@ lazy val pluginScalaVersions = Seq(
"2.12.13",
"2.12.14",
"2.12.15",
+ "2.12.16",
"2.13.0",
"2.13.1",
"2.13.2",
@@ -137,7 +138,12 @@ lazy val plugin = (project in file("plugin")).
).
settings(
mimaPreviousArtifacts := {
- Set("edu.berkeley.cs" % "chisel3-plugin" % "3.5.0" cross CrossVersion.full)
+ // There is not yet a 2.12.16 artifact, so suppress until 3.5.4 is released
+ if (scalaVersion.value == "2.12.16") {
+ Set()
+ } else {
+ Set("edu.berkeley.cs" % "chisel3-plugin" % "3.5.3" cross CrossVersion.full)
+ }
}
)
@@ -156,7 +162,7 @@ lazy val macros = (project in file("macros")).
settings(name := "chisel3-macros").
settings(commonSettings: _*).
settings(publishSettings: _*).
- settings(mimaPreviousArtifacts := Set("edu.berkeley.cs" %% "chisel3-macros" % "3.5.0"))
+ settings(mimaPreviousArtifacts := Set("edu.berkeley.cs" %% "chisel3-macros" % "3.5.3"))
lazy val firrtlRef = ProjectRef(workspaceDirectory / "firrtl", "firrtl")
@@ -170,7 +176,20 @@ lazy val core = (project in file("core")).
buildInfoKeys := Seq[BuildInfoKey](buildInfoPackage, version, scalaVersion, sbtVersion)
).
settings(publishSettings: _*).
- settings(mimaPreviousArtifacts := Set("edu.berkeley.cs" %% "chisel3-core" % "3.5.0")).
+ settings(
+ mimaPreviousArtifacts := Set("edu.berkeley.cs" %% "chisel3-core" % "3.5.3"),
+ mimaBinaryIssueFilters ++= Seq(
+ // Modified package private methods (https://github.com/lightbend/mima/issues/53)
+ ProblemFilters.exclude[DirectMissingMethodProblem]("chisel3.Data._computeName"),
+ ProblemFilters.exclude[DirectMissingMethodProblem]("chisel3.Data.forceName"),
+ ProblemFilters.exclude[DirectMissingMethodProblem]("chisel3.MemBase._computeName"),
+ ProblemFilters.exclude[DirectMissingMethodProblem]("chisel3.MemBase.forceName"),
+ ProblemFilters.exclude[DirectMissingMethodProblem]("chisel3.VerificationStatement._computeName"),
+ ProblemFilters.exclude[DirectMissingMethodProblem]("chisel3.VerificationStatement.forceName"),
+ ProblemFilters.exclude[DirectMissingMethodProblem]("chisel3.experimental.BaseModule._computeName"),
+ ProblemFilters.exclude[DirectMissingMethodProblem]("chisel3.experimental.BaseModule.forceName"),
+ )
+ ).
settings(
name := "chisel3-core",
scalacOptions := scalacOptions.value ++ Seq(
@@ -199,13 +218,17 @@ lazy val chisel = (project in file(".")).
dependsOn(core).
aggregate(macros, core, plugin).
settings(
- mimaPreviousArtifacts := Set("edu.berkeley.cs" %% "chisel3" % "3.5.0"),
+ mimaPreviousArtifacts := Set("edu.berkeley.cs" %% "chisel3" % "3.5.3"),
mimaBinaryIssueFilters ++= Seq(
// Modified package private methods (https://github.com/lightbend/mima/issues/53)
ProblemFilters.exclude[DirectMissingMethodProblem]("chisel3.stage.ChiselOptions.this"),
),
libraryDependencies += defaultVersions("treadle") % "test",
Test / scalacOptions += "-P:chiselplugin:genBundleElements",
+ // Forward doc command to unidoc
+ Compile / doc := (ScalaUnidoc / doc).value,
+ // Include unidoc as the ScalaDoc for publishing
+ Compile / packageDoc / mappings := (ScalaUnidoc / packageDoc / mappings).value,
scalacOptions in Test ++= Seq("-language:reflectiveCalls"),
scalacOptions in Compile in doc ++= Seq(
"-diagrams",
@@ -242,7 +265,7 @@ lazy val integrationTests = (project in file ("integration-tests")).
settings(chiselSettings: _*).
settings(usePluginSettings: _*).
settings(Seq(
- libraryDependencies += defaultVersions("chiseltest") % "test",
+ libraryDependencies += "edu.berkeley.cs" %% "chiseltest" % "0.5-SNAPSHOT" % "test"
))
lazy val docs = project // new documentation project
diff --git a/core/src/main/scala/chisel3/Aggregate.scala b/core/src/main/scala/chisel3/Aggregate.scala
index cc5b83d9..82c02cbc 100644
--- a/core/src/main/scala/chisel3/Aggregate.scala
+++ b/core/src/main/scala/chisel3/Aggregate.scala
@@ -226,8 +226,8 @@ sealed class Vec[T <: Data] private[chisel3] (gen: => T, val length: Int) extend
}
// Since all children are the same, we can just use the sample_element rather than all children
- // .get is safe because None means mixed directions, we only pass 1 so that's not possible
- direction = ActualDirection.fromChildren(Set(sample_element.direction), resolvedDirection).get
+ direction =
+ ActualDirection.fromChildren(Set(sample_element.direction), resolvedDirection).getOrElse(ActualDirection.Empty)
}
// Note: the constructor takes a gen() function instead of a Seq to enforce
@@ -321,6 +321,7 @@ sealed class Vec[T <: Data] private[chisel3] (gen: => T, val length: Int) extend
case ActualDirection.Bidirectional(ActualDirection.Default) | ActualDirection.Unspecified =>
SpecifiedDirection.Unspecified
case ActualDirection.Bidirectional(ActualDirection.Flipped) => SpecifiedDirection.Flip
+ case ActualDirection.Empty => SpecifiedDirection.Unspecified
}
// TODO port technically isn't directly child of this data structure, but the result of some
// muxes / demuxes. However, this does make access consistent with the top-level bindings.
diff --git a/core/src/main/scala/chisel3/Annotation.scala b/core/src/main/scala/chisel3/Annotation.scala
index e08557eb..c350fb30 100644
--- a/core/src/main/scala/chisel3/Annotation.scala
+++ b/core/src/main/scala/chisel3/Annotation.scala
@@ -20,6 +20,14 @@ trait ChiselAnnotation {
def toFirrtl: Annotation
}
+/** Enhanced interface for Annotations in Chisel
+ *
+ * Defines a conversion to corresponding FIRRTL Annotation(s)
+ */
+trait ChiselMultiAnnotation {
+ def toFirrtl: Seq[Annotation]
+}
+
/** Mixin for [[ChiselAnnotation]] that instantiates an associated FIRRTL Transform when this Annotation is present
* during a run of
* [[Driver$.execute(args:Array[String],dut:()=>chisel3\.RawModule)* Driver.execute]].
@@ -34,6 +42,9 @@ object annotate {
def apply(anno: ChiselAnnotation): Unit = {
Builder.annotations += anno
}
+ def apply(annos: ChiselMultiAnnotation): Unit = {
+ Builder.newAnnotations += annos
+ }
}
/** Marks that a module to be ignored in Dedup Transform in Firrtl pass
diff --git a/core/src/main/scala/chisel3/Bits.scala b/core/src/main/scala/chisel3/Bits.scala
index a135a8e5..72094a65 100644
--- a/core/src/main/scala/chisel3/Bits.scala
+++ b/core/src/main/scala/chisel3/Bits.scala
@@ -8,7 +8,13 @@ import chisel3.experimental.{FixedPoint, Interval}
import chisel3.internal._
import chisel3.internal.Builder.pushOp
import chisel3.internal.firrtl._
-import chisel3.internal.sourceinfo.{SourceInfo, SourceInfoTransform, SourceInfoWhiteboxTransform, UIntTransform}
+import chisel3.internal.sourceinfo.{
+ IntLiteralApplyTransform,
+ SourceInfo,
+ SourceInfoTransform,
+ SourceInfoWhiteboxTransform,
+ UIntTransform
+}
import chisel3.internal.firrtl.PrimOp._
import _root_.firrtl.{ir => firrtlir}
import _root_.firrtl.{constraint => firrtlconstraint}
@@ -94,10 +100,10 @@ sealed abstract class Bits(private[chisel3] val width: Width) extends Element wi
* @param x an index
* @return the specified bit
*/
- final def apply(x: BigInt): Bool = macro SourceInfoTransform.xArg
+ final def extract(x: BigInt): Bool = macro SourceInfoTransform.xArg
/** @group SourceInfoTransformMacro */
- final def do_apply(x: BigInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = {
+ final def do_extract(x: BigInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = {
if (x < 0) {
Builder.error(s"Negative bit indices are illegal (got $x)")
}
@@ -121,26 +127,48 @@ sealed abstract class Bits(private[chisel3] val width: Width) extends Element wi
*
* @param x an index
* @return the specified bit
- * @note convenience method allowing direct use of [[scala.Int]] without implicits
*/
- final def apply(x: Int): Bool = macro SourceInfoTransform.xArg
+ final def apply(x: BigInt): Bool = macro IntLiteralApplyTransform.safeApply
+
+ /** @group SourceInfoTransformMacro */
+ final def do_apply(x: BigInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool =
+ do_extract(x)
+
+ /** Returns the specified bit on this $coll as a [[Bool]], statically addressed.
+ *
+ * @param x an index
+ * @return the specified bit
+ */
+ final def apply(x: Int): Bool = macro IntLiteralApplyTransform.safeApply
/** @group SourceInfoTransformMacro */
- final def do_apply(x: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = apply(BigInt(x))
+ final def do_apply(x: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool =
+ do_extract(BigInt(x))
/** Returns the specified bit on this wire as a [[Bool]], dynamically addressed.
*
* @param x a hardware component whose value will be used for dynamic addressing
* @return the specified bit
*/
- final def apply(x: UInt): Bool = macro SourceInfoTransform.xArg
+ final def extract(x: UInt): Bool = macro SourceInfoTransform.xArg
/** @group SourceInfoTransformMacro */
- final def do_apply(x: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = {
+ final def do_extract(x: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool = {
val theBits = this >> x
theBits(0)
}
+ /** Returns the specified bit on this wire as a [[Bool]], dynamically addressed.
+ *
+ * @param x a hardware component whose value will be used for dynamic addressing
+ * @return the specified bit
+ */
+ final def apply(x: UInt): Bool = macro SourceInfoTransform.xArg
+
+ /** @group SourceInfoTransformMacro */
+ final def do_apply(x: UInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): Bool =
+ do_extract(x)
+
/** Returns a subset of bits on this $coll from `hi` to `lo` (inclusive), statically addressed.
*
* @example
@@ -193,7 +221,7 @@ sealed abstract class Bits(private[chisel3] val width: Width) extends Element wi
/** @group SourceInfoTransformMacro */
final def do_apply(x: BigInt, y: BigInt)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): UInt =
- apply(castToInt(x, "High index"), castToInt(y, "Low index"))
+ do_apply(castToInt(x, "High index"), castToInt(y, "Low index"))
private[chisel3] def unop[T <: Data](sourceInfo: SourceInfo, dest: T, op: PrimOp): T = {
requireIsHardware(this, "bits operated on")
diff --git a/core/src/main/scala/chisel3/BlackBox.scala b/core/src/main/scala/chisel3/BlackBox.scala
index f3fc2711..f618901f 100644
--- a/core/src/main/scala/chisel3/BlackBox.scala
+++ b/core/src/main/scala/chisel3/BlackBox.scala
@@ -71,11 +71,8 @@ package experimental {
val names = nameIds(classOf[ExtModule])
- // Name ports based on reflection
- for (port <- getModulePorts) {
- require(names.contains(port), s"Unable to name port $port in $this")
- port.setRef(ModuleIO(this, _namespace.name(names(port))))
- }
+ // Ports are named in the same way as regular Modules
+ namePorts(names)
// All suggestions are in, force names to every node.
// While BlackBoxes are not supposed to have an implementation, we still need to call
diff --git a/core/src/main/scala/chisel3/CompileOptions.scala b/core/src/main/scala/chisel3/CompileOptions.scala
index db773d6e..aca00d1f 100644
--- a/core/src/main/scala/chisel3/CompileOptions.scala
+++ b/core/src/main/scala/chisel3/CompileOptions.scala
@@ -6,22 +6,37 @@ import scala.language.experimental.macros
import scala.reflect.macros.blackbox.Context
trait CompileOptions {
- // Should Record connections require a strict match of fields.
- // If true and the same fields aren't present in both source and sink, a MissingFieldException,
- // MissingLeftFieldException, or MissingRightFieldException will be thrown.
+
+ /** Should Record connections require a strict match of fields.
+ *
+ * If true and the same fields aren't present in both source and sink, a MissingFieldException,
+ * MissingLeftFieldException, or MissingRightFieldException will be thrown.
+ */
val connectFieldsMustMatch: Boolean
- // When creating an object that takes a type argument, the argument must be unbound (a pure type).
+
+ /** When creating an object that takes a type argument, the argument must be unbound (a pure type). */
val declaredTypeMustBeUnbound: Boolean
- // If a connection operator fails, don't try the connection with the operands (source and sink) reversed.
+
+ /** If a connection operator fails, don't try the connection with the operands (source and sink) reversed. */
val dontTryConnectionsSwapped: Boolean
- // If connection directionality is not explicit, do not use heuristics to attempt to determine it.
+
+ /** If connection directionality is not explicit, do not use heuristics to attempt to determine it. */
val dontAssumeDirectionality: Boolean
- // Check that referenced Data have actually been declared.
+
+ /** Check that referenced Data have actually been declared. */
val checkSynthesizable: Boolean
- // Require explicit assignment of DontCare to generate "x is invalid"
+
+ /** Require explicit assignment of DontCare to generate "x is invalid" */
val explicitInvalidate: Boolean
- // Should the reset type of Module be a Bool or a Reset
+
+ /** Should the reset type of Module be a Bool or a Reset */
val inferModuleReset: Boolean
+
+ /** If marked true, then any Module which consumes `inferModuleReset=false` must also mix in [[RequireSyncReset]] */
+ def migrateInferModuleReset: Boolean = false
+
+ /** Should connects emit as firrtl <= instead of <- */
+ def emitStrictConnects: Boolean = true
}
object CompileOptions {
@@ -36,6 +51,7 @@ object CompileOptions {
}
object ExplicitCompileOptions {
+
case class CompileOptionsClass(
// Should Record connections require a strict match of fields.
// If true and the same fields aren't present in both source and sink, a MissingFieldException,
@@ -65,7 +81,30 @@ object ExplicitCompileOptions {
checkSynthesizable = false,
explicitInvalidate = false,
inferModuleReset = false
- )
+ ) {
+ override def migrateInferModuleReset = false
+ override def emitStrictConnects = false
+ override def copy(
+ connectFieldsMustMatch: Boolean = false,
+ declaredTypeMustBeUnbound: Boolean = false,
+ dontTryConnectionsSwapped: Boolean = false,
+ dontAssumeDirectionality: Boolean = false,
+ checkSynthesizable: Boolean = false,
+ explicitInvalidate: Boolean = false,
+ inferModuleReset: Boolean = false
+ ) = new CompileOptionsClass(
+ connectFieldsMustMatch,
+ declaredTypeMustBeUnbound,
+ dontTryConnectionsSwapped,
+ dontAssumeDirectionality,
+ checkSynthesizable,
+ explicitInvalidate,
+ inferModuleReset
+ ) {
+ override def migrateInferModuleReset = false
+ override def emitStrictConnects = false
+ }
+ }
// Collection of "strict" connection compile options, preferred for new code.
implicit val Strict = new CompileOptionsClass(
@@ -76,5 +115,30 @@ object ExplicitCompileOptions {
checkSynthesizable = true,
explicitInvalidate = true,
inferModuleReset = true
- )
+ ) {
+
+ override def migrateInferModuleReset = false
+ override def emitStrictConnects = true
+
+ override def copy(
+ connectFieldsMustMatch: Boolean = true,
+ declaredTypeMustBeUnbound: Boolean = true,
+ dontTryConnectionsSwapped: Boolean = true,
+ dontAssumeDirectionality: Boolean = true,
+ checkSynthesizable: Boolean = true,
+ explicitInvalidate: Boolean = true,
+ inferModuleReset: Boolean = true
+ ) = new CompileOptionsClass(
+ connectFieldsMustMatch,
+ declaredTypeMustBeUnbound,
+ dontTryConnectionsSwapped,
+ dontAssumeDirectionality,
+ checkSynthesizable,
+ explicitInvalidate,
+ inferModuleReset
+ ) {
+ override def migrateInferModuleReset = false
+ override def emitStrictConnects = true
+ }
+ }
}
diff --git a/core/src/main/scala/chisel3/Data.scala b/core/src/main/scala/chisel3/Data.scala
index f468335e..592ebe25 100644
--- a/core/src/main/scala/chisel3/Data.scala
+++ b/core/src/main/scala/chisel3/Data.scala
@@ -12,6 +12,7 @@ import chisel3.internal.firrtl._
import chisel3.internal.sourceinfo.{DeprecatedSourceInfo, SourceInfo, SourceInfoTransform, UnlocatableSourceInfo}
import scala.collection.immutable.LazyList // Needed for 2.12 alias
+import scala.reflect.ClassTag
import scala.util.Try
/** User-specified directions.
@@ -157,6 +158,31 @@ package experimental {
target.direction
}
+ private def hasBinding[B <: ConstrainedBinding: ClassTag](target: Data) = {
+ target.topBindingOpt match {
+ case Some(b: B) => true
+ case _ => false
+ }
+ }
+
+ /** Check if a given `Data` is an IO port
+ * @param x the `Data` to check
+ * @return `true` if x is an IO port, `false` otherwise
+ */
+ def isIO(x: Data): Boolean = hasBinding[PortBinding](x)
+
+ /** Check if a given `Data` is a Wire
+ * @param x the `Data` to check
+ * @return `true` if x is a Wire, `false` otherwise
+ */
+ def isWire(x: Data): Boolean = hasBinding[WireBinding](x)
+
+ /** Check if a given `Data` is a Reg
+ * @param x the `Data` to check
+ * @return `true` if x is a Reg, `false` otherwise
+ */
+ def isReg(x: Data): Boolean = hasBinding[RegBinding](x)
+
/** Check if two Chisel types are the same type.
* Internally, this is dispatched to each Chisel type's
* `typeEquivalent` function for each type to determine
@@ -570,6 +596,7 @@ abstract class Data extends HasId with NamedComponent with SourceInfoDoc {
private[chisel3] def badConnect(that: Data)(implicit sourceInfo: SourceInfo): Unit =
throwException(s"cannot connect ${this} and ${that}")
+
private[chisel3] def connect(
that: Data
)(
@@ -583,6 +610,9 @@ abstract class Data extends HasId with NamedComponent with SourceInfoDoc {
case _: ReadOnlyBinding => throwException(s"Cannot reassign to read-only $this")
case _ => // fine
}
+ }
+ if (connectCompileOptions.emitStrictConnects) {
+
try {
MonoConnect.connect(sourceInfo, connectCompileOptions, this, that, Builder.referenceUserModule)
} catch {
@@ -610,6 +640,8 @@ abstract class Data extends HasId with NamedComponent with SourceInfoDoc {
case (_: DontCareBinding, _) => throw BiConnect.DontCareCantBeSink
case _ => // fine
}
+ }
+ if (connectCompileOptions.emitStrictConnects) {
try {
BiConnect.connect(sourceInfo, connectCompileOptions, this, that, Builder.referenceUserModule)
} catch {
@@ -866,7 +898,7 @@ trait WireFactory {
x.bind(WireBinding(Builder.forcedUserModule, Builder.currentWhen))
pushCommand(DefWire(sourceInfo, x))
- if (!compileOptions.explicitInvalidate) {
+ if (!compileOptions.explicitInvalidate || Builder.currentModule.get.isInstanceOf[ImplicitInvalidate]) {
pushCommand(DefInvalid(sourceInfo, x.ref))
}
diff --git a/core/src/main/scala/chisel3/Module.scala b/core/src/main/scala/chisel3/Module.scala
index 84139630..ba2d2e32 100644
--- a/core/src/main/scala/chisel3/Module.scala
+++ b/core/src/main/scala/chisel3/Module.scala
@@ -141,6 +141,15 @@ abstract class Module(implicit moduleCompileOptions: CompileOptions) extends Raw
// Top module and compatibility mode use Bool for reset
// Note that a Definition elaboration will lack a parent, but still not be a Top module
val inferReset = (_parent.isDefined || Builder.inDefinition) && moduleCompileOptions.inferModuleReset
+ if (moduleCompileOptions.migrateInferModuleReset && !moduleCompileOptions.inferModuleReset) {
+ this match {
+ case _: RequireSyncReset => // Good! It's been migrated.
+ case _ => // Bad! It hasn't been migrated.
+ Builder.error(
+ s"$desiredName is not inferring its module reset, but has not been marked `RequireSyncReset`. Please extend this trait."
+ )
+ }
+ }
if (inferReset) Reset() else Bool()
}
@@ -266,7 +275,7 @@ package internal {
private[chisel3] def setRefAndPortsRef(namespace: Namespace): Unit = {
val record = _portsRecord
// Use .forceName to re-use default name resolving behavior
- record.forceName(None, default = this.desiredName, namespace)
+ record.forceName(default = this.desiredName, namespace)
// Now take the Ref that forceName set and convert it to the correct Arg
val instName = record.getRef match {
case Ref(name) => name
@@ -377,7 +386,7 @@ package internal {
clonePorts.setAllParents(Some(cloneParent))
cloneParent._portsRecord = clonePorts
// Normally handled during Module construction but ClonePorts really lives in its parent's parent
- if (!compileOptions.explicitInvalidate) {
+ if (!compileOptions.explicitInvalidate || Builder.currentModule.get.isInstanceOf[ImplicitInvalidate]) {
// FIXME This almost certainly doesn't work since clonePorts is not a real thing...
pushCommand(DefInvalid(sourceInfo, clonePorts.ref))
}
@@ -486,6 +495,27 @@ package experimental {
*/
private[chisel3] def initializeInParent(parentCompileOptions: CompileOptions): Unit
+ private[chisel3] def namePorts(names: HashMap[HasId, String]): Unit = {
+ for (port <- getModulePorts) {
+ port._computeName(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,""" +
+ " name is already taken by another port!"
+ )
+ }
+ port.setRef(ModuleIO(this, _namespace.name(name)))
+ case None =>
+ Builder.error(
+ s"Unable to name port $port in $this, " +
+ "try making it a public field of the Module"
+ )
+ port.setRef(ModuleIO(this, "<UNNAMED>"))
+ }
+ }
+ }
+
//
// Chisel Internals
//
diff --git a/core/src/main/scala/chisel3/Printable.scala b/core/src/main/scala/chisel3/Printable.scala
index a616f2b0..78655517 100644
--- a/core/src/main/scala/chisel3/Printable.scala
+++ b/core/src/main/scala/chisel3/Printable.scala
@@ -63,57 +63,76 @@ object Printable {
*/
def pack(fmt: String, data: Data*): Printable = {
val args = data.toIterator
-
// Error handling
def carrotAt(index: Int) = (" " * index) + "^"
def errorMsg(index: Int) =
s"""| fmt = "$fmt"
| ${carrotAt(index)}
| data = ${data.mkString(", ")}""".stripMargin
- def getArg(i: Int): Data = {
+
+ def checkArg(i: Int): Unit = {
if (!args.hasNext) {
val msg = "has no matching argument!\n" + errorMsg(i)
// Exception wraps msg in s"Format Specifier '$msg'"
throw new MissingFormatArgumentException(msg)
}
- args.next()
+ val _ = args.next()
}
+ var iter = 0
+ var curr_start = 0
+ val buf = mutable.ListBuffer.empty[String]
+ while (iter < fmt.size) {
+ // Encountered % which is either
+ // 1. Describing a format specifier.
+ // 2. Literal Percent
+ // 3. Dangling percent - most likely due to a typo - intended literal percent or forgot the specifier.
+ // Try to give meaningful error reports
+ if (fmt(iter) == '%') {
+ if (iter != fmt.size - 1 && (fmt(iter + 1) != '%' && !fmt(iter + 1).isWhitespace)) {
+ checkArg(iter)
+ buf += fmt.substring(curr_start, iter)
+ curr_start = iter
+ iter += 1
+ }
- val pables = mutable.ListBuffer.empty[Printable]
- var str = ""
- var percent = false
- for ((c, i) <- fmt.zipWithIndex) {
- if (percent) {
- val arg = c match {
- case FirrtlFormat(x) => FirrtlFormat(x.toString, getArg(i))
- case 'n' => Name(getArg(i))
- case 'N' => FullName(getArg(i))
- case '%' => Percent
- case x =>
- val msg = s"Illegal format specifier '$x'!\n" + errorMsg(i)
- throw new UnknownFormatConversionException(msg)
+ // Last character is %.
+ else if (iter == fmt.size - 1) {
+ val msg = s"Trailing %\n" + errorMsg(fmt.size - 1)
+ throw new UnknownFormatConversionException(msg)
+ }
+
+ // A lone %
+ else if (fmt(iter + 1).isWhitespace) {
+ val msg = s"Unescaped % - add % if literal or add proper specifier if not\n" + errorMsg(iter + 1)
+ throw new UnknownFormatConversionException(msg)
+ }
+
+ // A literal percent - hence increment by 2.
+ else {
+ iter += 2
}
- pables += PString(str.dropRight(1)) // remove format %
- pables += arg
- str = ""
- percent = false
- } else {
- str += c
- percent = c == '%'
}
- }
- if (percent) {
- val msg = s"Trailing %\n" + errorMsg(fmt.size - 1)
- throw new UnknownFormatConversionException(msg)
+
+ // Normal progression
+ else {
+ iter += 1
+ }
}
require(
!args.hasNext,
s"Too many arguments! More format specifier(s) expected!\n" +
errorMsg(fmt.size)
)
+ buf += fmt.substring(curr_start, iter)
+
+ // The string received as an input to pack is already
+ // treated i.e. escape sequences are processed.
+ // Since StringContext API assumes the parts are un-treated
+ // treatEscapes is called within the implemented custom interpolators.
+ // The literal \ needs to be escaped before sending to the custom cf interpolator.
- pables += PString(str)
- Printables(pables)
+ val bufEscapeBackSlash = buf.map(_.replace("\\", "\\\\"))
+ StringContext(bufEscapeBackSlash.toSeq: _*).cf(data: _*)
}
}
diff --git a/core/src/main/scala/chisel3/RawModule.scala b/core/src/main/scala/chisel3/RawModule.scala
index 12b6a76a..f2ce4c70 100644
--- a/core/src/main/scala/chisel3/RawModule.scala
+++ b/core/src/main/scala/chisel3/RawModule.scala
@@ -43,25 +43,20 @@ abstract class RawModule(implicit moduleCompileOptions: CompileOptions) extends
val compileOptions = moduleCompileOptions
- private[chisel3] def namePorts(names: HashMap[HasId, String]): Unit = {
- for (port <- getModulePorts) {
- 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,""" +
- " name is already taken by another port!"
- )
- }
- port.setRef(ModuleIO(this, _namespace.name(name)))
- case None =>
- Builder.error(
- s"Unable to name port $port in $this, " +
- "try making it a public field of the Module"
- )
- port.setRef(ModuleIO(this, "<UNNAMED>"))
+ // This could be factored into a common utility
+ private def canBeNamed(id: HasId): Boolean = id match {
+ case d: Data =>
+ d.binding match {
+ case Some(_: ConstrainedBinding) => true
+ case _ => false
}
- }
+ case b: BaseModule => true
+ case m: MemBase[_] => true
+ // These names don't affect hardware
+ case _: VerificationStatement => false
+ // While the above should be comprehensive, since this is used in warning we want to be careful
+ // to never accidentally have a match error
+ case _ => false
}
private[chisel3] override def generateComponent(): Option[Component] = {
@@ -74,8 +69,24 @@ abstract class RawModule(implicit moduleCompileOptions: CompileOptions) extends
namePorts(names)
// Then everything else gets named
+ val warnReflectiveNaming = Builder.warnReflectiveNaming
for ((node, name) <- names) {
- node.suggestName(name)
+ node match {
+ case d: HasId if warnReflectiveNaming && canBeNamed(d) =>
+ val result = d._suggestNameCheck(name)
+ result match {
+ case None => // All good, no warning
+ case Some((oldName, oldPrefix)) =>
+ val prevName = buildName(oldName, oldPrefix.reverse)
+ val newName = buildName(name, Nil)
+ val msg = s"[module ${this.name}] '$prevName' is renamed by reflection to '$newName'. " +
+ s"Chisel 3.6 removes reflective naming so the name will remain '$prevName'."
+ Builder.warningNoLoc(msg)
+ }
+ // Note that unnamable things end up here (eg. literals), this is supporting backwards
+ // compatibility
+ case _ => node.suggestName(name)
+ }
}
// All suggestions are in, force names to every node.
@@ -83,26 +94,26 @@ abstract class RawModule(implicit moduleCompileOptions: CompileOptions) extends
id match {
case id: ModuleClone[_] => id.setRefAndPortsRef(_namespace) // special handling
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: 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: BaseModule => id.forceName(default = id.desiredName, _namespace)
+ case id: MemBase[_] => id.forceName(default = "MEM", _namespace)
+ case id: stop.Stop => id.forceName(default = "stop", _namespace)
+ case id: assert.Assert => id.forceName(default = "assert", _namespace)
+ case id: assume.Assume => id.forceName(default = "assume", _namespace)
+ case id: cover.Cover => id.forceName(default = "cover", _namespace)
+ case id: printf.Printf => id.forceName(default = "printf", _namespace)
case id: Data =>
if (id.isSynthesizable) {
id.topBinding match {
case OpBinding(_, _) =>
- id.forceName(Some(""), default = "T", _namespace)
+ id.forceName(default = "_T", _namespace)
case MemoryPortBinding(_, _) =>
- id.forceName(None, default = "MPORT", _namespace)
+ id.forceName(default = "MPORT", _namespace)
case PortBinding(_) =>
- id.forceName(None, default = "PORT", _namespace)
+ id.forceName(default = "PORT", _namespace)
case RegBinding(_, _) =>
- id.forceName(None, default = "REG", _namespace)
+ id.forceName(default = "REG", _namespace)
case WireBinding(_, _) =>
- id.forceName(Some(""), default = "WIRE", _namespace)
+ id.forceName(default = "_WIRE", _namespace)
case _ => // don't name literals
}
} // else, don't name unbound types
@@ -136,7 +147,7 @@ abstract class RawModule(implicit moduleCompileOptions: CompileOptions) extends
// Generate IO invalidation commands to initialize outputs as unused,
// unless the client wants explicit control over their generation.
val invalidateCommands = {
- if (!compileOptions.explicitInvalidate) {
+ if (!compileOptions.explicitInvalidate || this.isInstanceOf[ImplicitInvalidate]) {
getModulePorts.map { port => DefInvalid(UnlocatableSourceInfo, port.ref) }
} else {
Seq()
@@ -150,7 +161,7 @@ abstract class RawModule(implicit moduleCompileOptions: CompileOptions) extends
private[chisel3] def initializeInParent(parentCompileOptions: CompileOptions): Unit = {
implicit val sourceInfo = UnlocatableSourceInfo
- if (!parentCompileOptions.explicitInvalidate) {
+ if (!parentCompileOptions.explicitInvalidate || Builder.currentModule.get.isInstanceOf[ImplicitInvalidate]) {
for (port <- getModulePorts) {
pushCommand(DefInvalid(sourceInfo, port.ref))
}
@@ -166,6 +177,9 @@ trait RequireSyncReset extends Module {
override private[chisel3] def mkReset: Bool = Bool()
}
+/** Mix with a [[RawModule]] to automatically connect DontCare to the module's ports, wires, and children instance IOs. */
+trait ImplicitInvalidate { self: RawModule => }
+
package object internal {
import scala.annotation.implicitNotFound
@@ -175,6 +189,41 @@ package object internal {
/** Marker trait for modules that are not true modules */
private[chisel3] trait PseudoModule extends BaseModule
+ /* Check if a String name is a temporary name */
+ def isTemp(name: String): Boolean = name.nonEmpty && name.head == '_'
+
+ /** Creates a name String from a prefix and a seed
+ * @param prefix The prefix associated with the seed (must be in correct order, *not* reversed)
+ * @param seed The seed for computing the name (if available)
+ */
+ def buildName(seed: String, prefix: Prefix): String = {
+ // Don't bother copying the String if there's no prefix
+ if (prefix.isEmpty) {
+ seed
+ } else {
+ // Using Java's String builder to micro-optimize appending a String excluding 1st character
+ // for temporaries
+ val builder = new java.lang.StringBuilder()
+ // Starting with _ is the indicator of a temporary
+ val temp = isTemp(seed)
+ // Make sure the final result is also a temporary if this is a temporary
+ if (temp) {
+ builder.append('_')
+ }
+ prefix.foreach { p =>
+ builder.append(p)
+ builder.append('_')
+ }
+ if (temp) {
+ // We've moved the leading _ to the front, drop it here
+ builder.append(seed, 1, seed.length)
+ } else {
+ builder.append(seed)
+ }
+ builder.toString
+ }
+ }
+
// Private reflective version of "val io" to maintain Chisel.Module semantics without having
// io as a virtual method. See https://github.com/freechipsproject/chisel3/pull/1550 for more
// information about the removal of "val io"
diff --git a/core/src/main/scala/chisel3/StrongEnum.scala b/core/src/main/scala/chisel3/StrongEnum.scala
index 6f9cce55..cd6f11ee 100644
--- a/core/src/main/scala/chisel3/StrongEnum.scala
+++ b/core/src/main/scala/chisel3/StrongEnum.scala
@@ -71,7 +71,7 @@ object EnumAnnotations {
}
import EnumAnnotations._
-abstract class EnumType(private val factory: EnumFactory, selfAnnotating: Boolean = true) extends Element {
+abstract class EnumType(private[chisel3] 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
diff --git a/core/src/main/scala/chisel3/experimental/dataview/package.scala b/core/src/main/scala/chisel3/experimental/dataview/package.scala
index c583c516..71ae2d8f 100644
--- a/core/src/main/scala/chisel3/experimental/dataview/package.scala
+++ b/core/src/main/scala/chisel3/experimental/dataview/package.scala
@@ -33,7 +33,7 @@ package object dataview {
// The names of views do not matter except for when a view is annotated. For Views that correspond
// To a single Data, we just forward the name of the Target. For Views that correspond to more
// than one Data, we return this assigned name but rename it in the Convert stage
- result.forceName(None, "view", Builder.viewNamespace)
+ result.forceName("view", Builder.viewNamespace)
result
}
}
diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala
index 59b4c692..36bf6f87 100644
--- a/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala
+++ b/core/src/main/scala/chisel3/experimental/hierarchy/Definition.scala
@@ -11,6 +11,7 @@ import chisel3.internal.sourceinfo.{DefinitionTransform, DefinitionWrapTransform
import chisel3.experimental.BaseModule
import chisel3.internal.BaseModule.IsClone
import firrtl.annotations.{IsModule, ModuleTarget}
+import firrtl.annotations.{IsModule, ModuleTarget, NoTargetAnnotation}
/** User-facing Definition type.
* Represents a definition of an object of type [[A]] which are marked as @instantiable
@@ -100,7 +101,10 @@ object Definition extends SourceInfoDoc {
implicit sourceInfo: SourceInfo,
compileOptions: CompileOptions
): Definition[T] = {
- val dynamicContext = new DynamicContext(Nil, Builder.captureContext().throwOnFirstError)
+ val dynamicContext = {
+ val context = Builder.captureContext()
+ new DynamicContext(Nil, context.throwOnFirstError, context.warnReflectiveNaming)
+ }
Builder.globalNamespace.copyTo(dynamicContext.globalNamespace)
dynamicContext.inDefinition = true
val (ir, module) = Builder.build(Module(proto), dynamicContext, false)
@@ -112,3 +116,11 @@ object Definition extends SourceInfoDoc {
}
}
+
+/** Stores a [[Definition]] that is imported so that its Instances can be
+ * compiled separately.
+ */
+case class ImportDefinitionAnnotation[T <: BaseModule with IsInstantiable](
+ definition: Definition[T],
+ overrideDefName: Option[String] = None)
+ extends NoTargetAnnotation
diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala
index cc926771..861023a1 100644
--- a/core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala
+++ b/core/src/main/scala/chisel3/experimental/hierarchy/Instance.scala
@@ -2,13 +2,15 @@
package chisel3.experimental.hierarchy
-import scala.collection.mutable.{ArrayBuffer, HashMap}
import scala.language.experimental.macros
import chisel3._
import chisel3.internal.BaseModule.{InstantiableClone, IsClone, ModuleClone}
+import chisel3.internal.Builder
import chisel3.internal.sourceinfo.{InstanceTransform, SourceInfo}
-import chisel3.experimental.BaseModule
+import chisel3.experimental.{BaseModule, ExtModule}
+import chisel3.internal.firrtl.{Component, DefBlackBox, DefModule, Port}
import firrtl.annotations.IsModule
+import chisel3.internal.throwException
/** User-facing Instance type.
* Represents a unique instance of type [[A]] which are marked as @instantiable
@@ -107,9 +109,39 @@ object Instance extends SourceInfoDoc {
implicit sourceInfo: SourceInfo,
compileOptions: CompileOptions
): Instance[T] = {
+ // Check to see if the module is already defined internally or externally
+ val existingMod = Builder.components.map {
+ case c: DefModule if c.id == definition.proto => Some(c)
+ case c: DefBlackBox if c.name == definition.proto.name => Some(c)
+ case _ => None
+ }.flatten
+
+ if (existingMod.isEmpty) {
+ // Add a Definition that will get emitted as an ExtModule so that FIRRTL
+ // does not complain about a missing element
+ val extModName = Builder.importDefinitionMap.getOrElse(
+ definition.proto.name,
+ throwException(
+ "Imported Definition information not found - possibly forgot to add ImportDefinition annotation?"
+ )
+ )
+ class EmptyExtModule extends ExtModule {
+ override def desiredName: String = extModName
+ override def generateComponent(): Option[Component] = {
+ require(!_closed, s"Can't generate $desiredName module more than once")
+ _closed = true
+ val firrtlPorts = definition.proto.getModulePorts.map { port => Port(port, port.specifiedDirection) }
+ val component = DefBlackBox(this, definition.proto.name, firrtlPorts, SpecifiedDirection.Unspecified, params)
+ Some(component)
+ }
+ }
+ Definition(new EmptyExtModule() {})
+ }
+
val ports = experimental.CloneModuleAsRecord(definition.proto)
val clone = ports._parent.get.asInstanceOf[ModuleClone[T]]
clone._madeFromDefinition = true
+
new Instance(Clone(clone))
}
diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala
index 46a38e7c..c83479b0 100644
--- a/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala
+++ b/core/src/main/scala/chisel3/experimental/hierarchy/Lookupable.scala
@@ -218,7 +218,7 @@ object Lookupable {
result.bind(newBinding)
result.setAllParents(Some(ViewParent))
- result.forceName(None, "view", Builder.viewNamespace)
+ result.forceName("view", Builder.viewNamespace)
result
}
diff --git a/core/src/main/scala/chisel3/experimental/package.scala b/core/src/main/scala/chisel3/experimental/package.scala
index 9b9c83f4..b1d9cae4 100644
--- a/core/src/main/scala/chisel3/experimental/package.scala
+++ b/core/src/main/scala/chisel3/experimental/package.scala
@@ -160,8 +160,42 @@ package object experimental {
* }
* }}}
*/
+ @deprecated(
+ "@chiselName and NoChiselNamePrefix have been replaced by the compiler plugin and AffectsChiselPrefix. Use these instead",
+ "Chisel 3.5"
+ )
trait NoChiselNamePrefix
+ /** Generate prefixes from values of this type in the Chisel compiler plugin
+ *
+ * Users can mixin this trait to tell the Chisel compiler plugin to include the names of
+ * vals of this type when generating prefixes for naming `Data` and `Mem` instances.
+ * This is generally useful whenever creating a `class` that contains `Data`, `Mem`,
+ * or `Module` instances but does not itself extend `Data` or `Module`.
+ *
+ * @see See [[https://www.chisel-lang.org/chisel3/docs/explanations/naming.html the compiler plugin documentation]] for more information on this process.
+ *
+ * @example {{{
+ * import chisel3._
+ * import chisel3.experimental.AffectsChiselPrefix
+ *
+ * class MyModule extends Module {
+ * // Note: This contains a Data but is not a named component itself
+ * class NotAData extends AffectsChiselPrefix {
+ * val value = Wire(Bool())
+ * }
+ *
+ * // Name with AffectsChiselPrefix: "nonData_value"
+ * // Name without AffectsChiselPrefix: "value"
+ * val nonData = new NotAData
+ *
+ * // Name with AffectsChiselPrefix: "nonData2_value"
+ * // Name without AffectsChiselPrefix: "value_1"
+ * val nonData2 = new NotAData
+ * }
+ */
+ trait AffectsChiselPrefix
+
object BundleLiterals {
implicit class AddBundleLiteralConstructor[T <: Record](x: T) {
def Lit(elems: (T => (Data, Data))*)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): T = {
diff --git a/core/src/main/scala/chisel3/internal/BiConnect.scala b/core/src/main/scala/chisel3/internal/BiConnect.scala
index 2d6c9e4a..e8fb2361 100644
--- a/core/src/main/scala/chisel3/internal/BiConnect.scala
+++ b/core/src/main/scala/chisel3/internal/BiConnect.scala
@@ -55,6 +55,24 @@ private[chisel3] object BiConnect {
* There is some cleverness in the use of internal try-catch to catch exceptions
* during the recursive decent and then rethrow them with extra information added.
* This gives the user a 'path' to where in the connections things went wrong.
+ *
+ * == Chisel Semantics and how they emit to firrtl ==
+ *
+ * 1. Strict Bi-Connect (all fields as seen by firrtl must match exactly)
+ * `a <= b`
+ *
+ * 2. Strict Bi-Connect (implemented as being field-blasted because we know all firrtl fields would not match exactly)
+ * `a.foo <= b.foo, b.bar <= a.bar`
+ *
+ * 3. Not-Strict Bi-Connect (firrtl will allow fields to not match exactly)
+ * `a <- b`
+ *
+ * 4. Mixed Semantic Bi-Connect (some fields need to be handled differently)
+ * `a.foo <= b.foo` (case 2), `b.bar <- a.bar` (case 3)
+ *
+ * - The decision on 1 vs 2 is based on structural type -- if same type once emitted to firrtl, emit 1, otherwise emit 2
+ * - 1/2 vs 3 is based on CompileOptions at connection point e.g. at `<>` , emit 3 if `emitStrictConnects = false` for either side
+ * - 4 is a special case of 2 turning into 3 for some subfields, when either side's subfield at `extends Bundle/Record` has `emitStrictConnects = false`
*/
def connect(
sourceInfo: SourceInfo,
@@ -140,8 +158,8 @@ private[chisel3] object BiConnect {
// Handle Records defined in Chisel._ code by emitting a FIRRTL bulk
// connect when possible and a partial connect otherwise
case pair @ (left_r: Record, right_r: Record) =>
- val notStrict =
- Seq(left_r.compileOptions, right_r.compileOptions).contains(ExplicitCompileOptions.NotStrict)
+ val emitStrictConnects: Boolean =
+ left_r.compileOptions.emitStrictConnects && right_r.compileOptions.emitStrictConnects
// chisel3 <> is commutative but FIRRTL <- is not
val flipConnection =
@@ -161,40 +179,38 @@ private[chisel3] object BiConnect {
)
) {
pushCommand(Connect(sourceInfo, leftReified.get.lref, rightReified.get.lref))
- } else if (notStrict) {
- newLeft.bulkConnect(newRight)(sourceInfo, ExplicitCompileOptions.NotStrict)
+ } else if (!emitStrictConnects) {
+ newLeft.legacyConnect(newRight)(sourceInfo)
} else {
recordConnect(sourceInfo, connectCompileOptions, left_r, right_r, context_mod)
}
- // Handle Records connected to DontCare (change to NotStrict)
+ // Handle Records connected to DontCare
case (left_r: Record, DontCare) =>
- left_r.compileOptions match {
- case ExplicitCompileOptions.NotStrict =>
- left.bulkConnect(right)(sourceInfo, ExplicitCompileOptions.NotStrict)
- case _ =>
- // For each field in left, descend with right
- for ((field, left_sub) <- left_r.elements) {
- try {
- connect(sourceInfo, connectCompileOptions, left_sub, right, context_mod)
- } catch {
- case BiConnectException(message) => throw BiConnectException(s".$field$message")
- }
+ if (!left_r.compileOptions.emitStrictConnects) {
+ left.legacyConnect(right)(sourceInfo)
+ } else {
+ // For each field in left, descend with right
+ for ((field, left_sub) <- left_r.elements) {
+ try {
+ connect(sourceInfo, connectCompileOptions, left_sub, right, context_mod)
+ } catch {
+ case BiConnectException(message) => throw BiConnectException(s".$field$message")
}
+ }
}
case (DontCare, right_r: Record) =>
- right_r.compileOptions match {
- case ExplicitCompileOptions.NotStrict =>
- left.bulkConnect(right)(sourceInfo, ExplicitCompileOptions.NotStrict)
- case _ =>
- // For each field in left, descend with right
- for ((field, right_sub) <- right_r.elements) {
- try {
- connect(sourceInfo, connectCompileOptions, left, right_sub, context_mod)
- } catch {
- case BiConnectException(message) => throw BiConnectException(s".$field$message")
- }
+ if (!right_r.compileOptions.emitStrictConnects) {
+ left.legacyConnect(right)(sourceInfo)
+ } else {
+ // For each field in left, descend with right
+ for ((field, right_sub) <- right_r.elements) {
+ try {
+ connect(sourceInfo, connectCompileOptions, left, right_sub, context_mod)
+ } catch {
+ case BiConnectException(message) => throw BiConnectException(s".$field$message")
}
+ }
}
// Left and right are different subtypes of Data so fail
diff --git a/core/src/main/scala/chisel3/internal/Builder.scala b/core/src/main/scala/chisel3/internal/Builder.scala
index 4180f580..61f94f8f 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.{Clone, Instance}
+import chisel3.experimental.hierarchy.{Clone, ImportDefinitionAnnotation, Instance}
import chisel3.internal.firrtl._
import chisel3.internal.naming._
import _root_.firrtl.annotations.{CircuitName, ComponentName, IsMember, ModuleName, Named, ReferenceTarget}
@@ -137,6 +137,17 @@ private[chisel3] trait HasId extends InstanceId {
this
}
+ // Private internal version of suggestName that tells you if the name changed
+ // Returns Some(old name, old prefix) if name changed, None otherwise
+ private[chisel3] def _suggestNameCheck(seed: => String): Option[(String, Prefix)] = {
+ val oldSeed = this.seedOpt
+ val oldPrefix = this.naming_prefix
+ suggestName(seed)
+ if (oldSeed.nonEmpty && (oldSeed != this.seedOpt || oldPrefix != this.naming_prefix)) {
+ Some(oldSeed.get -> oldPrefix)
+ } else None
+ }
+
/** Takes the first seed suggested. Multiple calls to this function will be ignored.
* If the final computed name conflicts with another name, it may get uniquified by appending
* a digit at the end.
@@ -166,37 +177,13 @@ private[chisel3] trait HasId extends InstanceId {
}
/** 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
*/
- 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
- * @return
- */
- def buildName(seed: String, prefix: Prefix): String = {
- val builder = new StringBuilder()
- prefix.foreach { p =>
- builder ++= p
- builder += '_'
- }
- builder ++= seed
- builder.toString
- }
-
- if (hasSeed) {
- Some(buildName(seedOpt.get, naming_prefix.reverse))
- } else {
- defaultSeed.map { default =>
- defaultPrefix match {
- case Some(p) => buildName(default, p :: naming_prefix.reverse)
- case None => buildName(default, naming_prefix.reverse)
- }
- }
- }
+ private[chisel3] def _computeName(defaultSeed: Option[String]): Option[String] = {
+ seedOpt
+ .orElse(defaultSeed)
+ .map(name => buildName(name, naming_prefix.reverse))
}
/** This resolves the precedence of [[autoSeed]] and [[suggestName]]
@@ -216,9 +203,9 @@ private[chisel3] trait HasId extends InstanceId {
// Uses a namespace to convert suggestion into a true name
// Will not do any naming if the reference already assigned.
// (e.g. tried to suggest a name to part of a Record)
- private[chisel3] def forceName(prefix: Option[String], default: => String, namespace: Namespace): Unit =
+ private[chisel3] def forceName(default: => String, namespace: Namespace): Unit =
if (_ref.isEmpty) {
- val candidate_name = _computeName(prefix, Some(default)).get
+ val candidate_name = _computeName(Some(default)).get
val available_name = namespace.name(candidate_name)
setRef(Ref(available_name))
// Clear naming prefix to free memory
@@ -240,7 +227,18 @@ 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 =>
+ // This is super hacky but this is just for a short term deprecation
+ // These accesses occur after Chisel elaboration so we cannot use the normal
+ // Builder.deprecated mechanism, we have to create our own one off ErrorLog and print the
+ // warning right away.
+ val errors = new ErrorLog
+ val logger = new _root_.logger.Logger(this.getClass.getName)
+ val msg = "Accessing the .instanceName or .toTarget of non-hardware Data is deprecated. " +
+ "This will become an error in Chisel 3.6."
+ errors.deprecated(msg, None)
+ errors.checkpoint(logger)
+ _computeName(None).get
}
// Helper for reifying views if they map to a single Target
@@ -363,10 +361,50 @@ private[chisel3] class ChiselContext() {
val viewNamespace = Namespace.empty
}
-private[chisel3] class DynamicContext(val annotationSeq: AnnotationSeq, val throwOnFirstError: Boolean) {
+private[chisel3] class DynamicContext(
+ val annotationSeq: AnnotationSeq,
+ val throwOnFirstError: Boolean,
+ val warnReflectiveNaming: Boolean) {
+ val importDefinitionAnnos = annotationSeq.collect { case a: ImportDefinitionAnnotation[_] => a }
+
+ // Map holding the actual names of extModules
+ // Pick the definition name by default in case not passed through annotation.
+ val importDefinitionMap = importDefinitionAnnos
+ .map(a => a.definition.proto.name -> a.overrideDefName.getOrElse(a.definition.proto.name))
+ .toMap
+
+ // Helper function which does 2 things
+ // 1. Ensure there are no repeated names for imported Definitions - both Proto Names as well as ExtMod Names
+ // 2. Return the distinct definition / extMod names
+ private def checkAndGeDistinctProtoExtModNames() = {
+ val importAllDefinitionProtoNames = importDefinitionAnnos.map { a => a.definition.proto.name }
+ val importDistinctDefinitionProtoNames = importDefinitionMap.keys.toSeq
+ val importAllDefinitionExtModNames = importDefinitionMap.toSeq.map(_._2)
+ val importDistinctDefinitionExtModNames = importAllDefinitionExtModNames.distinct
+
+ if (importDistinctDefinitionProtoNames.length < importAllDefinitionProtoNames.length) {
+ val duplicates = importAllDefinitionProtoNames.diff(importDistinctDefinitionProtoNames).mkString(", ")
+ throwException(s"Expected distinct imported Definition names but found duplicates for: $duplicates")
+ }
+ if (importDistinctDefinitionExtModNames.length < importAllDefinitionExtModNames.length) {
+ val duplicates = importAllDefinitionExtModNames.diff(importDistinctDefinitionExtModNames).mkString(", ")
+ throwException(s"Expected distinct overrideDef names but found duplicates for: $duplicates")
+ }
+ (importAllDefinitionProtoNames ++ importAllDefinitionExtModNames).distinct
+ }
+
val globalNamespace = Namespace.empty
+
+ // Ensure imported Definitions emit as ExtModules with the correct name so
+ // that instantiations will also use the correct name and prevent any name
+ // conflicts with Modules/Definitions in this elaboration
+ checkAndGeDistinctProtoExtModNames().foreach {
+ globalNamespace.name(_)
+ }
+
val components = ArrayBuffer[Component]()
val annotations = ArrayBuffer[ChiselAnnotation]()
+ val newAnnotations = ArrayBuffer[ChiselMultiAnnotation]()
var currentModule: Option[BaseModule] = None
/** Contains a mapping from a elaborated module to their aspect
@@ -432,8 +470,13 @@ private[chisel3] object Builder extends LazyLogging {
def globalNamespace: Namespace = dynamicContext.globalNamespace
def components: ArrayBuffer[Component] = dynamicContext.components
def annotations: ArrayBuffer[ChiselAnnotation] = dynamicContext.annotations
- def annotationSeq: AnnotationSeq = dynamicContext.annotationSeq
- def namingStack: NamingStack = dynamicContext.namingStack
+
+ // TODO : Unify this with annotations in the future - done this way for backward compatability
+ def newAnnotations: ArrayBuffer[ChiselMultiAnnotation] = dynamicContext.newAnnotations
+
+ def annotationSeq: AnnotationSeq = dynamicContext.annotationSeq
+ def namingStack: NamingStack = dynamicContext.namingStack
+ def importDefinitionMap: Map[String, String] = dynamicContext.importDefinitionMap
def unnamedViews: ArrayBuffer[Data] = dynamicContext.unnamedViews
def viewNamespace: Namespace = chiselContext.get.viewNamespace
@@ -480,7 +523,11 @@ private[chisel3] object Builder extends LazyLogging {
}
}
buildAggName(d).map { name =>
- pushPrefix(name)
+ if (isTemp(name)) {
+ pushPrefix(name.tail)
+ } else {
+ pushPrefix(name)
+ }
}.isDefined
}
@@ -621,6 +668,8 @@ private[chisel3] object Builder extends LazyLogging {
throwException("Error: No implicit reset.")
)
+ def warnReflectiveNaming: Boolean = dynamicContext.warnReflectiveNaming
+
// TODO(twigg): Ideally, binding checks and new bindings would all occur here
// However, rest of frontend can't support this yet.
def pushCommand[T <: Command](c: T): T = {
@@ -662,8 +711,9 @@ private[chisel3] object Builder extends LazyLogging {
throwException(m)
}
}
- def warning(m: => String): Unit = if (dynamicContextVar.value.isDefined) errors.warning(m)
- def deprecated(m: => String, location: Option[String] = None): Unit =
+ def warning(m: => String): Unit = if (dynamicContextVar.value.isDefined) errors.warning(m)
+ def warningNoLoc(m: => String): Unit = if (dynamicContextVar.value.isDefined) errors.warningNoLoc(m)
+ def deprecated(m: => String, location: Option[String] = None): Unit =
if (dynamicContextVar.value.isDefined) errors.deprecated(m, location)
/** Record an exception as an error, and throw it.
@@ -720,12 +770,12 @@ private[chisel3] object Builder extends LazyLogging {
logger.info("Elaborating design...")
val mod = f
if (forceModName) { // This avoids definition name index skipping with D/I
- mod.forceName(None, mod.name, globalNamespace)
+ mod.forceName(mod.name, globalNamespace)
}
errors.checkpoint(logger)
logger.info("Done elaborating.")
- (Circuit(components.last.name, components.toSeq, annotations.toSeq, makeViewRenameMap), mod)
+ (Circuit(components.last.name, components.toSeq, annotations.toSeq, makeViewRenameMap, newAnnotations.toSeq), mod)
}
}
initializeSingletons()
diff --git a/core/src/main/scala/chisel3/internal/Error.scala b/core/src/main/scala/chisel3/internal/Error.scala
index 62086870..3b0846eb 100644
--- a/core/src/main/scala/chisel3/internal/Error.scala
+++ b/core/src/main/scala/chisel3/internal/Error.scala
@@ -186,6 +186,11 @@ private[chisel3] class ErrorLog {
def warning(m: => String): Unit =
errors += new Warning(m, getUserLineNumber)
+ /** Log a warning message without a source locator */
+ def warningNoLoc(m: => String): Unit = {
+ errors += new Warning(m, None)
+ }
+
/** Emit an informational message */
@deprecated("This method will be removed in 3.5", "3.4")
def info(m: String): Unit =
diff --git a/core/src/main/scala/chisel3/internal/MonoConnect.scala b/core/src/main/scala/chisel3/internal/MonoConnect.scala
index 40056c89..31364804 100644
--- a/core/src/main/scala/chisel3/internal/MonoConnect.scala
+++ b/core/src/main/scala/chisel3/internal/MonoConnect.scala
@@ -210,7 +210,9 @@ private[chisel3] object MonoConnect {
}
// Source is DontCare - it may be connected to anything. It generates a defInvalid for the sink.
- case (sink, DontCare) => pushCommand(DefInvalid(sourceInfo, sink.lref))
+ case (_sink: Element, DontCare) =>
+ val sink = reify(_sink) // Handle views
+ pushCommand(DefInvalid(sourceInfo, sink.lref))
// DontCare as a sink is illegal.
case (DontCare, _) => throw DontCareCantBeSink
// Analog is illegal in mono connections.
diff --git a/core/src/main/scala/chisel3/internal/firrtl/IR.scala b/core/src/main/scala/chisel3/internal/firrtl/IR.scala
index 1ee8842f..dc9ab027 100644
--- a/core/src/main/scala/chisel3/internal/firrtl/IR.scala
+++ b/core/src/main/scala/chisel3/internal/firrtl/IR.scala
@@ -94,7 +94,7 @@ object Arg {
case Some(arg) => arg.name
case None =>
id match {
- case data: Data => data._computeName(None, Some("?")).get
+ case data: Data => data._computeName(Some("?")).get
case _ => "?"
}
}
@@ -861,7 +861,40 @@ case class DefBlackBox(
params: Map[String, Param])
extends Component
-case class Circuit(name: String, components: Seq[Component], annotations: Seq[ChiselAnnotation], renames: RenameMap) {
- def firrtlAnnotations: Iterable[Annotation] = annotations.flatMap(_.toFirrtl.update(renames))
+case class Circuit(
+ name: String,
+ components: Seq[Component],
+ @deprecated("Do not use annotations val of Circuit directly - use firrtlAnnotations instead. Will be removed in a future release",
+ "Chisel 3.5")
+ annotations: Seq[ChiselAnnotation],
+ renames: RenameMap,
+ @deprecated("Do not use newAnnotations val of Circuit directly - use firrtlAnnotations instead. Will be removed in a future release",
+ "Chisel 3.5")
+ newAnnotations: Seq[ChiselMultiAnnotation]) {
+
+ def this(name: String, components: Seq[Component], annotations: Seq[ChiselAnnotation], renames: RenameMap) =
+ this(name, components, annotations, renames, Seq.empty)
+
+ def firrtlAnnotations: Iterable[Annotation] =
+ annotations.flatMap(_.toFirrtl.update(renames)) ++ newAnnotations.flatMap(
+ _.toFirrtl.flatMap(_.update(renames))
+ )
+
+ def copy(
+ name: String = name,
+ components: Seq[Component] = components,
+ annotations: Seq[ChiselAnnotation] = annotations,
+ renames: RenameMap = renames
+ ) = Circuit(name, components, annotations, renames, newAnnotations)
+
+}
+object Circuit
+ extends scala.runtime.AbstractFunction4[String, Seq[Component], Seq[ChiselAnnotation], RenameMap, Circuit] {
+ def unapply(c: Circuit): Option[(String, Seq[Component], Seq[ChiselAnnotation], RenameMap)] = {
+ Some((c.name, c.components, c.annotations, c.renames))
+ }
+
+ def apply(name: String, components: Seq[Component], annotations: Seq[ChiselAnnotation], renames: RenameMap): Circuit =
+ new Circuit(name, components, annotations, renames)
}
diff --git a/core/src/main/scala/chisel3/package.scala b/core/src/main/scala/chisel3/package.scala
index bd088e21..87024683 100644
--- a/core/src/main/scala/chisel3/package.scala
+++ b/core/src/main/scala/chisel3/package.scala
@@ -1,10 +1,14 @@
// SPDX-License-Identifier: Apache-2.0
import chisel3.internal.firrtl.BinaryPoint
+import java.util.{MissingFormatArgumentException, UnknownFormatConversionException}
+import scala.collection.mutable
/** This package contains the main chisel3 API.
*/
package object chisel3 {
+ import internal.chiselRuntimeDeprecated
+ import internal.sourceinfo.DeprecatedSourceInfo
import internal.firrtl.{Port, Width}
import internal.Builder
@@ -37,13 +41,11 @@ package object chisel3 {
case bigint => Builder.error(s"Cannot convert $bigint to Bool, must be 0 or 1"); Bool.Lit(false)
}
- /** Int to UInt conversion, recommended style for constants.
- */
- def U: UInt = UInt.Lit(bigint, Width())
+ /** Int to UInt conversion, recommended style for constants. */
+ def U: UInt = UInt.Lit(bigint, Width()) // scalastyle:ignore method.name
- /** Int to SInt conversion, recommended style for constants.
- */
- def S: SInt = SInt.Lit(bigint, Width())
+ /** Int to SInt conversion, recommended style for constants. */
+ def S: SInt = SInt.Lit(bigint, Width()) // scalastyle:ignore method.name
/** Int to UInt conversion with specified width, recommended style for constants.
*/
@@ -210,29 +212,142 @@ package object chisel3 {
implicit class PrintableHelper(val sc: StringContext) extends AnyVal {
/** Custom string interpolator for generating Printables: p"..."
- * Will call .toString on any non-Printable arguments (mimicking s"...")
+ * mimicks s"..." for non-Printable data)
*/
def p(args: Any*): Printable = {
- sc.checkLengths(args) // Enforce sc.parts.size == pargs.size + 1
- val pargs: Seq[Option[Printable]] = args.map {
- case p: Printable => Some(p)
- case d: Data => Some(d.toPrintable)
- case any =>
- for {
- v <- Option(any) // Handle null inputs
- str = v.toString
- if !str.isEmpty // Handle empty Strings
- } yield PString(str)
+ // P interpolator does not treat % differently - hence need to add % before sending to cf.
+ val t = sc.parts.map(_.replaceAll("%", "%%"))
+ StringContext(t: _*).cf(args: _*)
+ }
+
+ /** Custom string interpolator for generating formatted Printables : cf"..."
+ *
+ * Enhanced version of scala's `f` interpolator.
+ * Each expression (argument) referenced within the string is
+ * converted to a particular Printable depending
+ * on the format specifier and type.
+ *
+ * ==== For Chisel types referenced within the String ====
+ *
+ * - <code>%n</code> - Returns [[Name]] Printable.
+ * - <code>%N</code> - Returns [[FullName]] Printable.
+ * - <code>%b,%d,%x,%c</code> - Only applicable for types of [[Bits]] or dreived from it. - returns ([[Binary]],[[Decimal]],
+ * [[Hexadecimal]],[[Character]]) Printable respectively.
+ * - Default - If no specifier given call [[Data.toPrintable]] on the Chisel Type.
+ *
+ * ==== For [[Printable]] type: ====
+ * No explicit format specifier supported - just return the Printable.
+ *
+ * ==== For regular scala types ====
+ * Call String.format with the argument and specifier.
+ * Default is %s if no specifier is given.
+ * Wrap the result in [[PString]] Printable.
+ *
+ * ==== For the parts of the StringContext ====
+ * Remove format specifiers and if literal percents (need to be escaped with %)
+ * are present convert them into [[Percent]] Printable.
+ * Rest of the string will be wrapped in [[PString]] Printable.
+ *
+ * @example
+ * {{{
+ *
+ * val w1 = 20.U // Chisel UInt type (which extends Bits)
+ * val f1 = 30.2 // Scala float type.
+ * val pable = cf"w1 = $w1%x f1 = $f1%2.2f. This is 100%% clear"
+ *
+ * // pable is as follows
+ * // Printables(List(PString(w1 = ), Hexadecimal(UInt<5>(20)), PString( f1 = ), PString(30.20), PString(. This is 100), Percent, PString( clear)))
+ * }}}
+ *
+ * @throws UnknownFormatConversionException
+ * if literal percent not escaped with % or if the format specifier is not supported
+ * for the specific type
+ *
+ * @throws StringContext.InvalidEscapeException
+ * if a `parts` string contains a backslash (`\`) character
+ * that does not start a valid escape sequence.
+ *
+ * @throws IllegalArgumentException
+ * if the number of `parts` in the enclosing `StringContext` does not exceed
+ * the number of arguments `arg` by exactly 1.
+ */
+ def cf(args: Any*): Printable = {
+
+ // Handle literal %
+ // Takes the part string -
+ // - this is assumed to not have any format specifiers - already handled / removed before calling this function.
+ // Only thing present is literal % if any which should ideally be with %%.
+ // If not - then flag an error.
+ // Return seq of Printables (either PString or Percent or both - nothing else
+ def percentSplitter(s: String): Seq[Printable] = {
+ if (s.isEmpty) Seq(PString(""))
+ else {
+ val pieces = s.split("%%").toList.flatMap { p =>
+ if (p.contains('%')) throw new UnknownFormatConversionException("Un-escaped % found")
+ // Wrap in PString and intersperse the escaped percentages
+ Seq(Percent, PString(p))
+ }
+ if (pieces.isEmpty) Seq(Percent)
+ else pieces.tail // Don't forget to drop the extra percent we put at the beginning
+ }
}
+
+ def extractFormatSpecifier(part: String): (Option[String], String) = {
+ // Check if part starts with a format specifier (with % - disambiguate with literal % checking the next character if needed to be %)
+ // In the case of %f specifier there is a chance that we need more information - so capture till the 1st letter (a-zA-Z).
+ // Example cf"This is $val%2.2f here" - parts - Seq("This is ","%2.2f here") - the format specifier here is %2.2f.
+ val endFmtIdx =
+ if (part.length > 1 && part(0) == '%' && part(1) != '%') part.indexWhere(_.isLetter)
+ else -1
+ val (fmt, rest) = part.splitAt(endFmtIdx + 1)
+
+ val fmtOpt = if (fmt.nonEmpty) Some(fmt) else None
+ (fmtOpt, rest)
+
+ }
+
+ sc.checkLengths(args) // Enforce sc.parts.size == pargs.size + 1
val parts = sc.parts.map(StringContext.treatEscapes)
- // Zip sc.parts and pargs together ito flat Seq
- // eg. Seq(sc.parts(0), pargs(0), sc.parts(1), pargs(1), ...)
- val seq = for { // append None because sc.parts.size == pargs.size + 1
- (literal, arg) <- parts.zip(pargs :+ None)
- optPable <- Seq(Some(PString(literal)), arg)
- pable <- optPable // Remove Option[_]
- } yield pable
- Printables(seq)
+ // The 1st part is assumed never to contain a format specifier.
+ // If the 1st part of a string is an argument - then the 1st part will be an empty String.
+ // So we need to parse parts following the 1st one to get the format specifiers if any
+ val partsAfterFirst = parts.tail
+
+ // Align parts to their potential specifiers
+ val pables = partsAfterFirst.zip(args).flatMap {
+ case (part, arg) => {
+ val (fmt, modP) = extractFormatSpecifier(part)
+ val fmtArg: Printable = arg match {
+ case d: Data => {
+ fmt match {
+ case Some("%n") => Name(d)
+ case Some("%N") => FullName(d)
+ case Some(fForm) if d.isInstanceOf[Bits] => FirrtlFormat(fForm.substring(1, 2), d)
+ case Some(x) => {
+ val msg = s"Illegal format specifier '$x' for Chisel Data type!\n"
+ throw new UnknownFormatConversionException(msg)
+ }
+ case None => d.toPrintable
+ }
+ }
+ case p: Printable => {
+ fmt match {
+ case Some(x) => {
+ val msg = s"Illegal format specifier '$x' for Chisel Printable type!\n"
+ throw new UnknownFormatConversionException(msg)
+ }
+ case None => p
+ }
+ }
+
+ // Generic case - use String.format (for example %d,%2.2f etc on regular Scala types)
+ case t => PString(fmt.getOrElse("%s").format(t))
+
+ }
+ Seq(fmtArg) ++ percentSplitter(modP)
+ }
+ }
+ Printables(percentSplitter(parts.head) ++ pables)
}
}
diff --git a/docs/src/appendix/experimental-features.md b/docs/src/appendix/experimental-features.md
index 92226f8f..a85704c2 100644
--- a/docs/src/appendix/experimental-features.md
+++ b/docs/src/appendix/experimental-features.md
@@ -9,7 +9,8 @@ Chisel has a number of new features that are worth checking out. This page is a
- [FixedPoint](#fixed-point)
- [Module Variants](#module-variants)
-- [Module Variants](#bundle-literals)
+- [Bundle Literals](#bundle-literals)
+- [Vec Literals](#vec-literals)
- [Interval Type](#interval-type)
- [Loading Memories for simulation or FPGA initialization](#loading-memories)
@@ -52,7 +53,10 @@ class Example extends RawModule {
chisel3.stage.ChiselStage.emitVerilog(new Example)
```
-Partial specification is allowed, defaulting any unconnected fields to 0 (regardless of type).
+Partial specification is allowed, which results in "invalidated fields" as
+described in [Unconnected Wires](../explanations/unconnected-wires).
+Note that this can be used with `RegInit` to construct partially reset registers as
+described in the [Cookbook](../cookbooks/cookbook#how-do-i-partially-reset-an-aggregate-reg).
```scala mdoc
class Example2 extends RawModule {
@@ -122,9 +126,10 @@ chisel3.stage.ChiselStage.emitVerilog(new VecExample1a)
```
The following examples all use the explicit form.
-With the explicit form partial specification is allowed.
-When used with as a `Reg` `reset` value, only specified indices of the `Reg`'s `Vec`
-will be reset
+With the explicit form partial specification is allowed, which results in
+"invalidated fields" as described in [Unconnected Wires](../explanations/unconnected-wires).
+Note that this can be used with `RegInit` to construct partially reset registers as
+described in the [Cookbook](../cookbooks/cookbook#how-do-i-partially-reset-an-aggregate-reg).
```scala mdoc
class VecExample2 extends RawModule {
diff --git a/docs/src/cookbooks/cookbook.md b/docs/src/cookbooks/cookbook.md
index b9e5db38..ab8e76d3 100644
--- a/docs/src/cookbooks/cookbook.md
+++ b/docs/src/cookbooks/cookbook.md
@@ -20,6 +20,7 @@ Please note that these examples make use of [Chisel's scala-style printing](../e
* [Can I make a 2D or 3D Vector?](#can-i-make-a-2D-or-3D-Vector)
* [How do I create a Vector of Registers?](#how-do-i-create-a-vector-of-registers)
* [How do I create a Reg of type Vec?](#how-do-i-create-a-reg-of-type-vec)
+ * [How do I partially reset an Aggregate Reg?](#how-do-i-partially-reset-an-aggregate-reg)
* Bundles
* [How do I deal with aliased Bundle fields?](#aliased-bundle-fields)
* [How do I create a finite state machine?](#how-do-i-create-a-finite-state-machine-fsm)
@@ -234,6 +235,45 @@ class Foo extends RawModule {
}
```
+
+### How do I partially reset an Aggregate Reg?
+
+The easiest way is to use a partially-specified [Bundle Literal](#../appendix/experimental-features#bundle-literals)
+or [Vec Literal](#../appendix/experimental-features#vec-literals) to match the type of the Reg.
+
+```scala mdoc:silent:reset
+import chisel3._
+import chisel3.experimental.BundleLiterals._
+
+class MyBundle extends Bundle {
+ val foo = UInt(8.W)
+ val bar = UInt(8.W)
+}
+
+class MyModule extends Module {
+ // Only .foo will be reset, .bar will have no reset value
+ val reg = RegInit((new MyBundle).Lit(_.foo -> 123.U))
+}
+```
+
+If your initial value is not a literal, or if you just prefer, you can use a
+Wire as the initial value for the Reg. Simply connect fields to `DontCare` that
+you do not wish to be reset.
+
+```scala mdoc:silent
+class MyModule2 extends Module {
+ val reg = RegInit({
+ // The wire could be constructed before the reg rather than in the RegInit scope,
+ // but this style has nice lexical scoping behavior, keeping the Wire private
+ val init = Wire(new MyBundle)
+ init := DontCare // No fields will be reset
+ init.foo := 123.U // Last connect override, .foo is reset
+ init
+ })
+}
+```
+
+
## Bundles
### <a name="aliased-bundle-fields"></a> How do I deal with aliased Bundle fields?
diff --git a/docs/src/explanations/chisel-type-vs-scala-type.md b/docs/src/explanations/chisel-type-vs-scala-type.md
new file mode 100644
index 00000000..6c311a21
--- /dev/null
+++ b/docs/src/explanations/chisel-type-vs-scala-type.md
@@ -0,0 +1,285 @@
+---
+layout: docs
+title: "Chisel Type vs Scala Type"
+section: "chisel3"
+---
+
+# Chisel Type vs Scala Type
+
+The Scala compiler cannot distinguish between Chisel's representation of hardware such as `false.B`, `Reg(Bool())`
+and pure Chisel types (e.g. `Bool()`). You can get runtime errors passing a Chisel type when hardware is expected, and vice versa.
+
+## Scala Type vs Chisel Type vs Hardware
+
+```scala mdoc:invisible
+import chisel3._
+import chisel3.stage.ChiselStage
+```
+
+The *Scala* type of the Data is recognized by the Scala compiler, such as `Bool`, `Decoupled[UInt]` or `MyBundle` in
+```scala mdoc:silent
+class MyBundle(w: Int) extends Bundle {
+ val foo = UInt(w.W)
+ val bar = UInt(w.W)
+}
+```
+
+The *Chisel* type of a `Data` is a Scala object. It captures all the fields actually present,
+by names, and their types including widths.
+For example, `MyBundle(3)` creates a Chisel Type with fields `foo: UInt(3.W), bar: UInt(3.W))`.
+
+Hardware is `Data` that is "bound" to synthesizable hardware. For example `false.B` or `Reg(Bool())`.
+The binding is what determines the actual directionality of each field, it is not a property of the Chisel type.
+
+A literal is a `Data` that is respresentable as a literal value without being wrapped in Wire, Reg, or IO.
+
+## Chisel Type vs Hardware vs Literals
+
+The below code demonstrates how objects with the same Scala type (`MyBundle`) can have different properties.
+
+```scala mdoc:silent
+import chisel3.experimental.BundleLiterals._
+
+class MyModule(gen: () => MyBundle) extends Module {
+ // Hardware Literal
+ val xType: MyBundle = new MyBundle(3) // - -
+ val dirXType: MyBundle = Input(new MyBundle(3)) // - -
+ val xReg: MyBundle = Reg(new MyBundle(3)) // x -
+ val xIO: MyBundle = IO(Input(new MyBundle(3))) // x -
+ val xRegInit: MyBundle = RegInit(xIO) // x -
+ val xLit: MyBundle = xType.Lit( // x x
+ _.foo -> 0.U(3.W),
+ _.bar -> 0.U(3.W)
+ )
+ val y: MyBundle = gen() // ? ?
+
+ // Need to initialize all hardware values
+ xReg := DontCare
+}
+```
+
+```scala mdoc:invisible
+// Just here to compile check the above
+ChiselStage.elaborate(new MyModule(() => new MyBundle(3)))
+```
+
+## Chisel Type vs Hardware -- Specific Functions and Errors
+
+`.asTypeOf` works for both hardware and Chisel type:
+
+```scala mdoc:silent
+ChiselStage.elaborate(new Module {
+ val chiselType = new MyBundle(3)
+ val hardware = Wire(new MyBundle(3))
+ hardware := DontCare
+ val a = 0.U.asTypeOf(chiselType)
+ val b = 0.U.asTypeOf(hardware)
+})
+```
+
+Can only `:=` to hardware:
+```scala mdoc:silent
+// Do this...
+ChiselStage.elaborate(new Module {
+ val hardware = Wire(new MyBundle(3))
+ hardware := DontCare
+})
+```
+```scala mdoc:crash
+// Not this...
+ChiselStage.elaborate(new Module {
+ val chiselType = new MyBundle(3)
+ chiselType := DontCare
+})
+```
+
+Can only `:=` from hardware:
+```scala mdoc:silent
+// Do this...
+ChiselStage.elaborate(new Module {
+ val hardware = IO(new MyBundle(3))
+ val moarHardware = Wire(new MyBundle(3))
+ moarHardware := DontCare
+ hardware := moarHardware
+})
+```
+```scala mdoc:crash
+// Not this...
+ChiselStage.elaborate(new Module {
+ val hardware = IO(new MyBundle(3))
+ val chiselType = new MyBundle(3)
+ hardware := chiselType
+})
+```
+
+Have to pass hardware to `chiselTypeOf`:
+```scala mdoc:silent
+// Do this...
+ChiselStage.elaborate(new Module {
+ val hardware = Wire(new MyBundle(3))
+ hardware := DontCare
+ val chiselType = chiselTypeOf(hardware)
+})
+```
+```scala mdoc:crash
+// Not this...
+ChiselStage.elaborate(new Module {
+ val chiselType = new MyBundle(3)
+ val crash = chiselTypeOf(chiselType)
+})
+```
+
+Have to pass hardware to `*Init`:
+```scala mdoc:silent
+// Do this...
+ChiselStage.elaborate(new Module {
+ val hardware = Wire(new MyBundle(3))
+ hardware := DontCare
+ val moarHardware = WireInit(hardware)
+})
+```
+```scala mdoc:crash
+// Not this...
+ChiselStage.elaborate(new Module {
+ val crash = WireInit(new MyBundle(3))
+})
+```
+
+Can't pass hardware to a `Wire`, `Reg`, `IO`:
+```scala mdoc:silent
+// Do this...
+ChiselStage.elaborate(new Module {
+ val hardware = Wire(new MyBundle(3))
+ hardware := DontCare
+})
+```
+```scala mdoc:crash
+// Not this...
+ChiselStage.elaborate(new Module {
+ val hardware = Wire(new MyBundle(3))
+ val crash = Wire(hardware)
+})
+```
+
+`.Lit` can only be called on Chisel type:
+```scala mdoc:silent
+// Do this...
+ChiselStage.elaborate(new Module {
+ val hardwareLit = (new MyBundle(3)).Lit(
+ _.foo -> 0.U,
+ _.bar -> 0.U
+ )
+})
+```
+```scala mdoc:crash
+//Not this...
+ChiselStage.elaborate(new Module {
+ val hardware = Wire(new MyBundle(3))
+ val crash = hardware.Lit(
+ _.foo -> 0.U,
+ _.bar -> 0.U
+ )
+})
+```
+
+Can only use a Chisel type within a `Bundle` definition:
+```scala mdoc:silent
+// Do this...
+ChiselStage.elaborate(new Module {
+ val hardware = Wire(new Bundle {
+ val nested = new MyBundle(3)
+ })
+ hardware := DontCare
+})
+```
+```scala mdoc:crash
+// Not this...
+ChiselStage.elaborate(new Module {
+ val crash = Wire(new Bundle {
+ val nested = Wire(new MyBundle(3))
+ })
+})
+```
+
+Can only call `directionOf` on Hardware:
+```scala mdoc:silent
+import chisel3.experimental.DataMirror
+
+class Child extends Module{
+ val hardware = IO(new MyBundle(3))
+ hardware := DontCare
+ val chiselType = new MyBundle(3)
+}
+```
+```scala mdoc:silent
+// Do this...
+ChiselStage.elaborate(new Module {
+ val child = Module(new Child())
+ child.hardware := DontCare
+ val direction = DataMirror.directionOf(child.hardware)
+})
+```
+```scala mdoc:crash
+// Not this...
+ChiselStage.elaborate(new Module {
+val child = Module(new Child())
+ child.hardware := DontCare
+ val direction = DataMirror.directionOf(child.chiselType)
+})
+```
+
+Can call `specifiedDirectionOf` on hardware or Chisel type:
+```scala mdoc:silent
+ChiselStage.elaborate(new Module {
+ val child = Module(new Child())
+ child.hardware := DontCare
+ val direction0 = DataMirror.specifiedDirectionOf(child.hardware)
+ val direction1 = DataMirror.specifiedDirectionOf(child.chiselType)
+})
+```
+
+## `.asInstanceOf` vs `.asTypeOf` vs `chiselTypeOf`
+
+`.asInstanceOf` is a Scala runtime cast, usually used for telling the compiler
+that you have more information than it can infer to convert Scala types:
+
+```scala mdoc:silent
+class ScalaCastingModule(gen: () => Bundle) extends Module {
+ val io = gen().asInstanceOf[MyBundle]
+ io.foo := 0.U
+}
+```
+
+This works if we do indeed have more information than the compiler:
+``` scala mdoc:silent
+ChiselStage.elaborate(new ScalaCastingModule( () => new MyBundle(3)))
+```
+
+But if we are wrong, we can get a Scala runtime exception:
+```scala mdoc:crash
+class NotMyBundle extends Bundle {val baz = Bool()}
+ChiselStage.elaborate(new ScalaCastingModule(() => new NotMyBundle()))
+```
+
+`.asTypeOf` is a conversion from one `Data` subclass to another.
+It is commonly used to assign data to all-zeros, as described in [this cookbook recipe](https://www.chisel-lang.org/chisel3/docs/cookbooks/cookbook.html#how-can-i-tieoff-a-bundlevec-to-0), but it can
+also be used (though not really recommended, as there is no checking on
+width matches) to convert one Chisel type to another:
+
+```scala mdoc
+class SimilarToMyBundle(w: Int) extends Bundle{
+ val foobar = UInt((2*w).W)
+}
+
+ChiselStage.emitVerilog(new Module {
+ val in = IO(Input(new MyBundle(3)))
+ val out = IO(Output(new SimilarToMyBundle(3)))
+
+ out := in.asTypeOf(out)
+})
+```
+
+In contrast to `asInstanceOf` and `asTypeOf`,
+`chiselTypeOf` is not a casting operation. It returns a Scala object which
+can be used as shown in the examples above to create more Chisel types and
+hardware with the same Chisel type as existing hardware.
diff --git a/docs/src/explanations/data-types.md b/docs/src/explanations/data-types.md
index 6ac6077b..67b8e0b9 100644
--- a/docs/src/explanations/data-types.md
+++ b/docs/src/explanations/data-types.md
@@ -1,6 +1,6 @@
---
layout: docs
-title: "Data Types"
+title: "Chisel Data Types"
section: "chisel3"
---
@@ -134,3 +134,4 @@ a <> b
a <> b
a <> c
```
+
diff --git a/docs/src/explanations/explanations.md b/docs/src/explanations/explanations.md
index 9e0227d5..762648d0 100644
--- a/docs/src/explanations/explanations.md
+++ b/docs/src/explanations/explanations.md
@@ -39,3 +39,4 @@ read these documents in the following order:
* [Unconnected Wires](unconnected-wires)
* [Annotations](annotations)
* [Deep Dive into Connection Operators](connection-operators)
+* [Chisel Type vs Scala Type](chisel-type-vs-scala-type)
diff --git a/docs/src/explanations/interfaces-and-connections.md b/docs/src/explanations/interfaces-and-connections.md
index 0fb8bae8..5d9cfd3c 100644
--- a/docs/src/explanations/interfaces-and-connections.md
+++ b/docs/src/explanations/interfaces-and-connections.md
@@ -150,7 +150,7 @@ Below we can see the resulting error for this example:
```scala mdoc:crash
ChiselStage.emitVerilog(new BlockWithTemporaryWires)
```
-For more details and information, see [Deep Dive into Connection Operators](connection-operators.md)
+For more details and information, see [Deep Dive into Connection Operators](connection-operators)
NOTE: When using `Chisel._` (compatibility mode) instead of `chisel3._`, the `:=` operator works in a bidirectional fashion similar to `<>`, but not exactly the same.
diff --git a/docs/src/explanations/naming.md b/docs/src/explanations/naming.md
index a9f21936..99797cb2 100644
--- a/docs/src/explanations/naming.md
+++ b/docs/src/explanations/naming.md
@@ -24,11 +24,11 @@ import chisel3.experimental.{prefix, noPrefix}
import chisel3.stage.ChiselStage
```
-With the release of Chisel 3.4, users should add the following line to their build.sbt settings to get the improved
-naming:
+With the release of Chisel 3.5, users are required to add the following line to
+their build.sbt settings:
```scala
-// chiselVersion is the String version (eg. "3.4.0")
+// chiselVersion is the String version (eg. "3.5.3")
addCompilerPlugin("edu.berkeley.cs" % "chisel3-plugin" % chiselVersion cross CrossVersion.full)
```
@@ -78,6 +78,29 @@ class Example2 extends Module {
ChiselStage.emitVerilog(new Example2)
```
+Prefixing can also be derived from the name of signals on the left-hand side of a connection.
+While this is not implemented via the compiler plugin, the behavior should feel similar:
+
+```scala mdoc
+class ConnectPrefixing extends Module {
+ val in = IO(Input(UInt(2.W)))
+ // val in = autoNameRecursively("in")(prefix("in")(IO(Input(UInt(2.W)))))
+
+ val out = IO(Output(UInt(2.W)))
+ // val out = autoNameRecursively("out")(prefix("out")(IO(Output(UInt(2.W)))))
+
+ out := { // technically this is not wrapped in autoNameRecursively nor prefix
+ // But the Chisel runtime will still use the name of `out` as a prefix
+ val double = in * in
+ // val double = autoNameRecursively("double")(prefix("double")(in * in))
+ double + 1.U
+ }
+}
+```
+```scala mdoc:verilog
+ChiselStage.emitVerilog(new ConnectPrefixing)
+```
+
Note that the naming also works if the hardware type is nested in an `Option` or a subtype of `Iterable`:
```scala mdoc
@@ -121,7 +144,7 @@ Users who desire a prefix are encouraged to provide one as [described below](#pr
### Prefixing
As shown above, the compiler plugin automatically attempts to prefix some of your signals for you. However, you as a
-user can also add your own prefixes. This is especially for ECO-type fixes where you need to add some logic to a module
+user can also add your own prefixes. This is especially useful for ECO-type fixes where you need to add some logic to a module
but don't want to influence other names in the module.
In the following example, we prefix additional logic with "ECO", where `Example4` is pre-ECO and `Example5` is post-ECO:
@@ -202,6 +225,96 @@ class Example8 extends Module {
ChiselStage.emitVerilog(new Example8)
```
+Note that using `.suggestName` does **not** affect prefixes derived from val names;
+however, it _can_ affect prefixes derived from connections (eg. `:=`):
+
+```scala mdoc
+class ConnectionPrefixExample extends Module {
+ val in0 = IO(Input(UInt(2.W)))
+ val in1 = IO(Input(UInt(2.W)))
+
+ val out0 = {
+ val port = IO(Output(UInt()))
+ // Even though this suggestName is before mul, the prefix used in this scope
+ // is derived from `val out0`, so this does not affect the name of mul
+ port.suggestName("foo")
+ // out0_mul
+ val mul = in0 * in1
+ port := mul + 1.U
+ port
+ }
+
+ val out1 = IO(Output(UInt()))
+ val out2 = IO(Output(UInt()))
+
+ out1 := {
+ // out1_sum
+ val sum = in0 + in1
+ sum + 1.U
+ }
+ // Comes after so does *not* affect prefix above
+ out1.suggestName("bar")
+
+ // Comes before so *does* affect prefix below
+ out2.suggestName("fizz")
+ out2 := {
+ // fizz_diff
+ val diff = in0 - in1
+ diff + 1.U
+ }
+}
+```
+```scala mdoc:verilog
+ChiselStage.emitVerilog(new ConnectionPrefixExample)
+```
+
+As this example illustrates, this behavior is slightly inconsistent so is subject to change in a future version of Chisel.
+
+
+### Behavior for "Unnamed signals" (aka "Temporaries")
+
+If you want to signify that the name of a signal does not matter, you can prefix the name of your val with `_`.
+Chisel will preserve the convention of leading `_` signifying an unnamed signal across prefixes.
+For example:
+
+```scala mdoc
+class TemporaryExample extends Module {
+ val in0 = IO(Input(UInt(2.W)))
+ val in1 = IO(Input(UInt(2.W)))
+
+ val out = {
+ val port = IO(Output(UInt()))
+ val _sum = in0 + in1
+ port := _sum + 1.U
+ port
+ }
+}
+```
+```scala mdoc:verilog
+ChiselStage.emitVerilog(new TemporaryExample)
+```
+
+If an unnamed signal is itself used to generate a prefix, the leading `_` will be ignored to avoid double `__` in the names of further nested signals.
+
+
+```scala mdoc
+class TemporaryPrefixExample extends Module {
+ val in0 = IO(Input(UInt(2.W)))
+ val in1 = IO(Input(UInt(2.W)))
+ val out = IO(Output(UInt()))
+
+ val _sum = {
+ val x = in0 + in1
+ x + 1.U
+ }
+ out := _sum & 0x2.U
+}
+```
+```scala mdoc:verilog
+ChiselStage.emitVerilog(new TemporaryPrefixExample)
+```
+
+
### Set a Module Name
If you want to specify the module's name (not the instance name of a module), you can always override the `desiredName`
diff --git a/macros/src/main/scala/chisel3/internal/naming/NamingAnnotations.scala b/macros/src/main/scala/chisel3/internal/naming/NamingAnnotations.scala
index b12826fc..01c3d4c1 100644
--- a/macros/src/main/scala/chisel3/internal/naming/NamingAnnotations.scala
+++ b/macros/src/main/scala/chisel3/internal/naming/NamingAnnotations.scala
@@ -207,6 +207,10 @@ class treedump extends StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro chisel3.internal.naming.DebugTransforms.treedump
}
@compileTimeOnly("enable macro paradise to expand macro annotations")
+@deprecated(
+ "Use chisel3.experimental.AffectsChiselPrefix instead. @chiselName will be removed in Chisel 3.6",
+ "Chisel 3.5"
+)
class chiselName extends StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro chisel3.internal.naming.NamingTransforms.chiselName
}
diff --git a/macros/src/main/scala/chisel3/internal/sourceinfo/SourceInfoTransform.scala b/macros/src/main/scala/chisel3/internal/sourceinfo/SourceInfoTransform.scala
index 3e310774..d772fd8b 100644
--- a/macros/src/main/scala/chisel3/internal/sourceinfo/SourceInfoTransform.scala
+++ b/macros/src/main/scala/chisel3/internal/sourceinfo/SourceInfoTransform.scala
@@ -249,3 +249,31 @@ class SourceInfoWhiteboxTransform(val c: whitebox.Context) extends AutoSourceTra
q"$thisObj.$doFuncTerm($that)($implicitSourceInfo, $implicitCompileOptions)"
}
}
+
+// Workaround for https://github.com/sbt/sbt/issues/3966
+object IntLiteralApplyTransform
+
+class IntLiteralApplyTransform(val c: Context) extends AutoSourceTransform {
+ import c.universe._
+
+ def safeApply(x: c.Tree): c.Tree = {
+ c.macroApplication match {
+ case q"$_.$clazz($lit).$func.apply($arg)" =>
+ if (
+ Set("U", "S").contains(func.toString) &&
+ Set("fromStringToLiteral", "fromIntToLiteral", "fromLongToIteral", "fromBigIntToLiteral").contains(
+ clazz.toString
+ )
+ ) {
+ val msg =
+ s"""Passing an Int to .$func is usually a mistake: It does *not* set the width but does a bit extract.
+ |Did you mean .$func($arg.W)?
+ |If you do want bit extraction, use .$func.extract($arg) instead.
+ |""".stripMargin
+ c.warning(c.enclosingPosition, msg)
+ }
+ case _ => // do nothing
+ }
+ q"$thisObj.$doFuncTerm($x)($implicitSourceInfo, $implicitCompileOptions)"
+ }
+}
diff --git a/plugin/src/main/scala/chisel3/internal/plugin/BundleComponent.scala b/plugin/src/main/scala/chisel3/internal/plugin/BundleComponent.scala
index e3ec0a04..eca3b158 100644
--- a/plugin/src/main/scala/chisel3/internal/plugin/BundleComponent.scala
+++ b/plugin/src/main/scala/chisel3/internal/plugin/BundleComponent.scala
@@ -84,6 +84,8 @@ private[plugin] class BundleComponent(val global: Global, arguments: ChiselPlugi
def isNullaryMethodNamed(name: String, defdef: DefDef): Boolean =
defdef.name.decodedName.toString == name && defdef.tparams.isEmpty && defdef.vparamss.isEmpty
+ def isVarArgs(sym: Symbol): Boolean = definitions.isRepeatedParamType(sym.tpe)
+
def getConstructorAndParams(body: List[Tree]): (Option[DefDef], Seq[Symbol]) = {
val paramAccessors = mutable.ListBuffer[Symbol]()
var primaryConstructor: Option[DefDef] = None
@@ -134,7 +136,9 @@ private[plugin] class BundleComponent(val global: Global, arguments: ChiselPlugi
// Make this.<ref>
val select = gen.mkAttributedSelect(thiz.asInstanceOf[Tree], p)
// Clone any Data parameters to avoid field aliasing, need full clone to include direction
- if (isData(vp.symbol)) cloneTypeFull(select.asInstanceOf[Tree]) else select
+ val cloned = if (isData(vp.symbol)) cloneTypeFull(select.asInstanceOf[Tree]) else select
+ // Need to splat varargs
+ if (isVarArgs(vp.symbol)) q"$cloned: _*" else cloned
})
val tparamList = bundle.tparams.map { t => Ident(t.symbol) }
diff --git a/plugin/src/main/scala/chisel3/internal/plugin/ChiselComponent.scala b/plugin/src/main/scala/chisel3/internal/plugin/ChiselComponent.scala
index eced652b..dd9f24fb 100644
--- a/plugin/src/main/scala/chisel3/internal/plugin/ChiselComponent.scala
+++ b/plugin/src/main/scala/chisel3/internal/plugin/ChiselComponent.scala
@@ -78,10 +78,21 @@ class ChiselComponent(val global: Global, arguments: ChiselPluginArguments)
}
}
- private val shouldMatchData: Type => Boolean = shouldMatchGen(tq"chisel3.Data")
- private val shouldMatchDataOrMem: Type => Boolean = shouldMatchGen(tq"chisel3.Data", tq"chisel3.MemBase[_]")
- private val shouldMatchModule: Type => Boolean = shouldMatchGen(tq"chisel3.experimental.BaseModule")
- private val shouldMatchInstance: Type => Boolean = shouldMatchGen(tq"chisel3.experimental.hierarchy.Instance[_]")
+ private val shouldMatchData: Type => Boolean = shouldMatchGen(tq"chisel3.Data")
+ // Checking for all chisel3.internal.NamedComponents, but since it is internal, we instead have
+ // to match the public subtypes
+ private val shouldMatchNamedComp: Type => Boolean =
+ shouldMatchGen(
+ tq"chisel3.Data",
+ tq"chisel3.MemBase[_]",
+ tq"chisel3.VerificationStatement"
+ )
+ private val shouldMatchModule: Type => Boolean = shouldMatchGen(tq"chisel3.experimental.BaseModule")
+ private val shouldMatchInstance: Type => Boolean = shouldMatchGen(tq"chisel3.experimental.hierarchy.Instance[_]")
+ private val shouldMatchChiselPrefixed: Type => Boolean =
+ shouldMatchGen(
+ tq"chisel3.experimental.AffectsChiselPrefix"
+ )
// Given a type tree, infer the type and return it
private def inferType(t: Tree): Type = localTyper.typed(t, nsc.Mode.TYPEmode).tpe
@@ -168,22 +179,38 @@ class ChiselComponent(val global: Global, arguments: ChiselPluginArguments)
// Check if a subtree is a candidate
case dd @ ValDef(mods, name, tpt, rhs) if okVal(dd) =>
val tpe = inferType(tpt)
+ val isData = shouldMatchData(tpe)
+ val isNamedComp = isData || shouldMatchNamedComp(tpe)
+ val isPrefixed = isNamedComp || shouldMatchChiselPrefixed(tpe)
+
// If a Data and in a Bundle, just get the name but not a prefix
- if (shouldMatchData(tpe) && inBundle(dd)) {
+ if (isData && inBundle(dd)) {
val str = stringFromTermName(name)
val newRHS = transform(rhs) // chisel3.internal.plugin.autoNameRecursively
val named = q"chisel3.internal.plugin.autoNameRecursively($str)($newRHS)"
treeCopy.ValDef(dd, mods, name, tpt, localTyper.typed(named))
}
// If a Data or a Memory, get the name and a prefix
- else if (shouldMatchDataOrMem(tpe)) {
+ else if (isData || isPrefixed) {
val str = stringFromTermName(name)
+ // Starting with '_' signifies a temporary, we ignore it for prefixing because we don't
+ // want double "__" in names when the user is just specifying a temporary
+ val prefix = if (str.head == '_') str.tail else str
val newRHS = transform(rhs)
- val prefixed = q"chisel3.experimental.prefix.apply[$tpt](name=$str)(f=$newRHS)"
- val named = q"chisel3.internal.plugin.autoNameRecursively($str)($prefixed)"
+ val prefixed = q"chisel3.experimental.prefix.apply[$tpt](name=$prefix)(f=$newRHS)"
+
+ val named =
+ if (isNamedComp) {
+ // Only name named components (not things that are merely prefixed)
+ q"chisel3.internal.plugin.autoNameRecursively($str)($prefixed)"
+ } else {
+ prefixed
+ }
+
treeCopy.ValDef(dd, mods, name, tpt, localTyper.typed(named))
- // If an instance, just get a name but no prefix
- } else if (shouldMatchModule(tpe)) {
+ }
+ // If an instance, just get a name but no prefix
+ else if (shouldMatchModule(tpe)) {
val str = stringFromTermName(name)
val newRHS = transform(rhs)
val named = q"chisel3.internal.plugin.autoNameRecursively($str)($newRHS)"
diff --git a/src/main/scala/chisel3/aop/injecting/InjectingAspect.scala b/src/main/scala/chisel3/aop/injecting/InjectingAspect.scala
index ba873c23..087bdae2 100644
--- a/src/main/scala/chisel3/aop/injecting/InjectingAspect.scala
+++ b/src/main/scala/chisel3/aop/injecting/InjectingAspect.scala
@@ -58,7 +58,8 @@ abstract class InjectorAspect[T <: RawModule, M <: RawModule](
final def toAnnotation(modules: Iterable[M], circuit: String, moduleNames: Seq[String]): AnnotationSeq = {
RunFirrtlTransformAnnotation(new InjectingTransform) +: modules.map { module =>
val chiselOptions = view[ChiselOptions](annotationsInAspect)
- val dynamicContext = new DynamicContext(annotationsInAspect, chiselOptions.throwOnFirstError)
+ val dynamicContext =
+ new DynamicContext(annotationsInAspect, chiselOptions.throwOnFirstError, chiselOptions.warnReflectiveNaming)
// Add existing module names into the namespace. If injection logic instantiates new modules
// which would share the same name, they will get uniquified accordingly
moduleNames.foreach { n =>
diff --git a/src/main/scala/chisel3/stage/ChiselAnnotations.scala b/src/main/scala/chisel3/stage/ChiselAnnotations.scala
index e046319d..eda05a7d 100644
--- a/src/main/scala/chisel3/stage/ChiselAnnotations.scala
+++ b/src/main/scala/chisel3/stage/ChiselAnnotations.scala
@@ -79,6 +79,22 @@ case object ThrowOnFirstErrorAnnotation
}
+/** Warn when reflective naming changes names of signals */
+case object WarnReflectiveNamingAnnotation
+ extends NoTargetAnnotation
+ with ChiselOption
+ with HasShellOptions
+ with Unserializable {
+
+ val options = Seq(
+ new ShellOption[Unit](
+ longOption = "warn:reflective-naming",
+ toAnnotationSeq = _ => Seq(this),
+ helpText = "Warn when reflective naming changes the name of signals (3.6 migration)"
+ )
+ )
+}
+
/** An [[firrtl.annotations.Annotation]] storing a function that returns a Chisel module
* @param gen a generator function
*/
diff --git a/src/main/scala/chisel3/stage/ChiselCli.scala b/src/main/scala/chisel3/stage/ChiselCli.scala
index f38bf50c..8c5eb79a 100644
--- a/src/main/scala/chisel3/stage/ChiselCli.scala
+++ b/src/main/scala/chisel3/stage/ChiselCli.scala
@@ -10,6 +10,7 @@ trait ChiselCli { this: Shell =>
NoRunFirrtlCompilerAnnotation,
PrintFullStackTraceAnnotation,
ThrowOnFirstErrorAnnotation,
+ WarnReflectiveNamingAnnotation,
ChiselOutputFileAnnotation,
ChiselGeneratorAnnotation
)
diff --git a/src/main/scala/chisel3/stage/ChiselOptions.scala b/src/main/scala/chisel3/stage/ChiselOptions.scala
index 7e4305fa..a03f3d7b 100644
--- a/src/main/scala/chisel3/stage/ChiselOptions.scala
+++ b/src/main/scala/chisel3/stage/ChiselOptions.scala
@@ -5,24 +5,27 @@ package chisel3.stage
import chisel3.internal.firrtl.Circuit
class ChiselOptions private[stage] (
- val runFirrtlCompiler: Boolean = true,
- val printFullStackTrace: Boolean = false,
- val throwOnFirstError: Boolean = false,
- val outputFile: Option[String] = None,
- val chiselCircuit: Option[Circuit] = None) {
+ val runFirrtlCompiler: Boolean = true,
+ val printFullStackTrace: Boolean = false,
+ val throwOnFirstError: Boolean = false,
+ val warnReflectiveNaming: Boolean = false,
+ val outputFile: Option[String] = None,
+ val chiselCircuit: Option[Circuit] = None) {
private[stage] def copy(
- runFirrtlCompiler: Boolean = runFirrtlCompiler,
- printFullStackTrace: Boolean = printFullStackTrace,
- throwOnFirstError: Boolean = throwOnFirstError,
- outputFile: Option[String] = outputFile,
- chiselCircuit: Option[Circuit] = chiselCircuit
+ runFirrtlCompiler: Boolean = runFirrtlCompiler,
+ printFullStackTrace: Boolean = printFullStackTrace,
+ throwOnFirstError: Boolean = throwOnFirstError,
+ warnReflectiveNaming: Boolean = warnReflectiveNaming,
+ outputFile: Option[String] = outputFile,
+ chiselCircuit: Option[Circuit] = chiselCircuit
): ChiselOptions = {
new ChiselOptions(
runFirrtlCompiler = runFirrtlCompiler,
printFullStackTrace = printFullStackTrace,
throwOnFirstError = throwOnFirstError,
+ warnReflectiveNaming = warnReflectiveNaming,
outputFile = outputFile,
chiselCircuit = chiselCircuit
)
diff --git a/src/main/scala/chisel3/stage/package.scala b/src/main/scala/chisel3/stage/package.scala
index b1064c05..10c8c524 100644
--- a/src/main/scala/chisel3/stage/package.scala
+++ b/src/main/scala/chisel3/stage/package.scala
@@ -15,11 +15,12 @@ package object stage {
def view(options: AnnotationSeq): ChiselOptions = options.collect { case a: ChiselOption => a }
.foldLeft(new ChiselOptions()) { (c, x) =>
x match {
- case NoRunFirrtlCompilerAnnotation => c.copy(runFirrtlCompiler = false)
- case PrintFullStackTraceAnnotation => c.copy(printFullStackTrace = true)
- case ThrowOnFirstErrorAnnotation => c.copy(throwOnFirstError = true)
- case ChiselOutputFileAnnotation(f) => c.copy(outputFile = Some(f))
- case ChiselCircuitAnnotation(a) => c.copy(chiselCircuit = Some(a))
+ case NoRunFirrtlCompilerAnnotation => c.copy(runFirrtlCompiler = false)
+ case PrintFullStackTraceAnnotation => c.copy(printFullStackTrace = true)
+ case ThrowOnFirstErrorAnnotation => c.copy(throwOnFirstError = true)
+ case WarnReflectiveNamingAnnotation => c.copy(warnReflectiveNaming = true)
+ case ChiselOutputFileAnnotation(f) => c.copy(outputFile = Some(f))
+ case ChiselCircuitAnnotation(a) => c.copy(chiselCircuit = Some(a))
}
}
diff --git a/src/main/scala/chisel3/stage/phases/Elaborate.scala b/src/main/scala/chisel3/stage/phases/Elaborate.scala
index 55331cb4..ba29e5f2 100644
--- a/src/main/scala/chisel3/stage/phases/Elaborate.scala
+++ b/src/main/scala/chisel3/stage/phases/Elaborate.scala
@@ -29,8 +29,10 @@ class Elaborate extends Phase {
case ChiselGeneratorAnnotation(gen) =>
val chiselOptions = view[ChiselOptions](annotations)
try {
+ val context =
+ new DynamicContext(annotations, chiselOptions.throwOnFirstError, chiselOptions.warnReflectiveNaming)
val (circuit, dut) =
- Builder.build(Module(gen()), new DynamicContext(annotations, chiselOptions.throwOnFirstError))
+ Builder.build(Module(gen()), context)
Seq(ChiselCircuitAnnotation(circuit), DesignAnnotation(dut))
} catch {
/* if any throwable comes back and we're in "stack trace trimming" mode, then print an error and trim the stack trace
diff --git a/src/main/scala/chisel3/util/Arbiter.scala b/src/main/scala/chisel3/util/Arbiter.scala
index 220a12b1..06821a25 100644
--- a/src/main/scala/chisel3/util/Arbiter.scala
+++ b/src/main/scala/chisel3/util/Arbiter.scala
@@ -6,7 +6,6 @@
package chisel3.util
import chisel3._
-import chisel3.internal.naming.chiselName // can't use chisel3_ version because of compile order
/** IO bundle definition for an Arbiter, which takes some number of ready-valid inputs and outputs
* (selects) at most one.
@@ -115,7 +114,6 @@ class LockingArbiter[T <: Data](gen: T, n: Int, count: Int, needsLock: Option[T
* consumer.io.in <> arb.io.out
* }}}
*/
-@chiselName
class RRArbiter[T <: Data](val gen: T, val n: Int) extends LockingRRArbiter[T](gen, n, 1)
/** Hardware module that is used to sequence n producers into 1 consumer.
@@ -131,7 +129,6 @@ class RRArbiter[T <: Data](val gen: T, val n: Int) extends LockingRRArbiter[T](g
* consumer.io.in <> arb.io.out
* }}}
*/
-@chiselName
class Arbiter[T <: Data](val gen: T, val n: Int) extends Module {
val io = IO(new ArbiterIO(gen, n))
diff --git a/src/main/scala/chisel3/util/BitPat.scala b/src/main/scala/chisel3/util/BitPat.scala
index d27fee14..7cb80e54 100644
--- a/src/main/scala/chisel3/util/BitPat.scala
+++ b/src/main/scala/chisel3/util/BitPat.scala
@@ -5,6 +5,8 @@ package chisel3.util
import scala.language.experimental.macros
import chisel3._
import chisel3.internal.sourceinfo.{SourceInfo, SourceInfoTransform}
+import scala.collection.mutable
+import scala.util.hashing.MurmurHash3
object BitPat {
@@ -253,6 +255,9 @@ sealed class BitPat(val value: BigInt, val mask: BigInt, val width: Int)
def =/=(that: UInt): Bool = macro SourceInfoTransform.thatArg
def ##(that: BitPat): BitPat = macro SourceInfoTransform.thatArg
+ override def hashCode: Int =
+ MurmurHash3.seqHash(Seq(this.value, this.mask, this.width))
+
/** @group SourceInfoTransformMacro */
def do_apply(x: Int)(implicit sourceInfo: SourceInfo, compileOptions: CompileOptions): BitPat = {
do_apply(x, x)
@@ -348,15 +353,29 @@ sealed class BitPat(val value: BigInt, val mask: BigInt, val width: Int)
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) => "?"
- }
+ def rawString: String = _rawString
+
+ // This is micro-optimized and memoized because it is used for lots of BitPat operations
+ private lazy val _rawString: String = {
+ val sb = new StringBuilder(width)
+ var i = 0
+ while (i < width) {
+ val bitIdx = width - i - 1
+ val char =
+ if (mask.testBit(bitIdx)) {
+ if (value.testBit(bitIdx)) {
+ '1'
+ } else {
+ '0'
+ }
+ } else {
+ '?'
+ }
+ sb += char
+ i += 1
}
- .mkString
+ sb.result()
+ }
override def toString = s"BitPat($rawString)"
}
diff --git a/src/main/scala/chisel3/util/Bitwise.scala b/src/main/scala/chisel3/util/Bitwise.scala
index 8abe3645..92ebddb4 100644
--- a/src/main/scala/chisel3/util/Bitwise.scala
+++ b/src/main/scala/chisel3/util/Bitwise.scala
@@ -24,13 +24,16 @@ object FillInterleaved {
*
* Output data-equivalent to in(size(in)-1) (n times) ## ... ## in(1) (n times) ## in(0) (n times)
*/
- def apply(n: Int, in: UInt): UInt = apply(n, in.asBools)
+ def apply(@deprecatedName('n, "Chisel 3.5") n: Int, @deprecatedName('in, "Chisel 3.5") in: UInt): UInt =
+ apply(n, in.asBools)
/** Creates n repetitions of each bit of x in order.
*
* Output data-equivalent to in(size(in)-1) (n times) ## ... ## in(1) (n times) ## in(0) (n times)
*/
- def apply(n: Int, in: Seq[Bool]): UInt = Cat(in.map(Fill(n, _)).reverse)
+ def apply(@deprecatedName('n, "Chisel 3.5") n: Int, @deprecatedName('in, "Chisel 3.5") in: Seq[Bool]): UInt = Cat(
+ in.map(Fill(n, _)).reverse
+ )
}
/** Returns the number of bits set (value is 1 or true) in the input signal.
@@ -45,9 +48,9 @@ object FillInterleaved {
* }}}
*/
object PopCount {
- def apply(in: Iterable[Bool]): UInt = SeqUtils.count(in.toSeq)
+ def apply(@deprecatedName('in, "Chisel 3.5") in: Iterable[Bool]): UInt = SeqUtils.count(in.toSeq)
- def apply(in: Bits): UInt = apply((0 until in.getWidth).map(in(_)))
+ def apply(@deprecatedName('in, "Chisel 3.5") in: Bits): UInt = apply((0 until in.getWidth).map(in(_)))
}
/** Create repetitions of the input using a tree fanout topology.
@@ -65,7 +68,7 @@ object Fill {
* Output data-equivalent to x ## x ## ... ## x (n repetitions).
* @throws java.lang.IllegalArgumentException if `n` is less than zero
*/
- def apply(n: Int, x: UInt): UInt = {
+ def apply(@deprecatedName('n, "Chisel 3.5") n: Int, @deprecatedName('x, "Chisel 3.5") x: UInt): UInt = {
n match {
case _ if n < 0 => throw new IllegalArgumentException(s"n (=$n) must be nonnegative integer.")
case 0 => UInt(0.W)
@@ -111,5 +114,5 @@ object Reverse {
Cat(doit(in(half - 1, 0), half), doit(in(length - 1, half), length - half))
}
- def apply(in: UInt): UInt = doit(in, in.getWidth)
+ def apply(@deprecatedName('in, "Chisel 3.5") in: UInt): UInt = doit(in, in.getWidth)
}
diff --git a/src/main/scala/chisel3/util/Cat.scala b/src/main/scala/chisel3/util/Cat.scala
index c5adce56..3224ec03 100644
--- a/src/main/scala/chisel3/util/Cat.scala
+++ b/src/main/scala/chisel3/util/Cat.scala
@@ -19,7 +19,9 @@ object Cat {
/** Concatenates the argument data elements, in argument order, together. The first argument
* forms the most significant bits, while the last argument forms the least significant bits.
*/
- def apply[T <: Bits](a: T, r: T*): UInt = apply(a :: r.toList)
+ def apply[T <: Bits](@deprecatedName('a, "Chisel 3.5") a: T, @deprecatedName('r, "Chisel 3.5") r: T*): UInt = apply(
+ a :: r.toList
+ )
/** Concatenates the data elements of the input sequence, in reverse sequence order, together.
* The first element of the sequence forms the most significant bits, while the last element
@@ -28,5 +30,5 @@ object Cat {
* Equivalent to r(0) ## r(1) ## ... ## r(n-1).
* @note This returns a `0.U` if applied to a zero-element `Vec`.
*/
- def apply[T <: Bits](r: Seq[T]): UInt = SeqUtils.asUInt(r.reverse)
+ def apply[T <: Bits](@deprecatedName('r, "Chisel 3.5") r: Seq[T]): UInt = SeqUtils.asUInt(r.reverse)
}
diff --git a/src/main/scala/chisel3/util/CircuitMath.scala b/src/main/scala/chisel3/util/CircuitMath.scala
index df60f059..9e4890a9 100644
--- a/src/main/scala/chisel3/util/CircuitMath.scala
+++ b/src/main/scala/chisel3/util/CircuitMath.scala
@@ -6,7 +6,6 @@
package chisel3.util
import chisel3._
-import chisel3.internal.naming.chiselName // can't use chisel3_ version because of compile order
/** Returns the base-2 integer logarithm of an UInt.
*
@@ -22,7 +21,6 @@ object Log2 {
/** Returns the base-2 integer logarithm of the least-significant `width` bits of an UInt.
*/
- @chiselName
def apply(x: Bits, width: Int): UInt = {
if (width < 2) {
0.U
diff --git a/src/main/scala/chisel3/util/Counter.scala b/src/main/scala/chisel3/util/Counter.scala
index ef1eff9f..be6e3257 100644
--- a/src/main/scala/chisel3/util/Counter.scala
+++ b/src/main/scala/chisel3/util/Counter.scala
@@ -3,7 +3,7 @@
package chisel3.util
import chisel3._
-import chisel3.internal.naming.chiselName // can't use chisel3_ version because of compile order
+import chisel3.experimental.AffectsChiselPrefix
/** Used to generate an inline (logic directly in the containing Module, no internal Module is created)
* hardware counter.
@@ -27,8 +27,7 @@ import chisel3.internal.naming.chiselName // can't use chisel3_ version because
* }
* }}}
*/
-@chiselName
-class Counter private (r: Range, oldN: Option[Int] = None) {
+class Counter private (r: Range, oldN: Option[Int] = None) extends AffectsChiselPrefix {
require(r.length > 0, s"Counter range cannot be empty, got: $r")
require(r.start >= 0 && r.end >= 0, s"Counter range must be positive, got: $r")
@@ -113,7 +112,6 @@ object Counter {
* @return tuple of the counter value and whether the counter will wrap (the value is at
* maximum and the condition is true).
*/
- @chiselName
def apply(cond: Bool, n: Int): (UInt, Bool) = {
val c = new Counter(n)
val wrap = WireInit(false.B)
@@ -129,7 +127,6 @@ object Counter {
* @return tuple of the counter value and whether the counter will wrap (the value is at
* maximum and the condition is true).
*/
- @chiselName
def apply(r: Range, enable: Bool = true.B, reset: Bool = false.B): (UInt, Bool) = {
val c = new Counter(r)
val wrap = WireInit(false.B)
diff --git a/src/main/scala/chisel3/util/Decoupled.scala b/src/main/scala/chisel3/util/Decoupled.scala
index 5c71a4ea..b21bd04f 100644
--- a/src/main/scala/chisel3/util/Decoupled.scala
+++ b/src/main/scala/chisel3/util/Decoupled.scala
@@ -9,6 +9,8 @@ import chisel3._
import chisel3.experimental.{requireIsChiselType, DataMirror, Direction}
import chisel3.internal.naming._ // can't use chisel3_ version because of compile order
+import scala.annotation.nowarn
+
/** An I/O Bundle containing 'valid' and 'ready' signals that handshake
* the transfer of data stored in the 'bits' subfield.
* The base protocol implied by the directionality is that
@@ -97,7 +99,22 @@ object ReadyValidIO {
* of ready or valid.
* @param gen the type of data to be wrapped in DecoupledIO
*/
-class DecoupledIO[+T <: Data](gen: T) extends ReadyValidIO[T](gen)
+class DecoupledIO[+T <: Data](gen: T) extends ReadyValidIO[T](gen) {
+
+ /** Applies the supplied functor to the bits of this interface, returning a new
+ * typed DecoupledIO interface.
+ * @param f The function to apply to this DecoupledIO's 'bits' with return type B
+ * @return a new DecoupledIO of type B
+ */
+ def map[B <: Data](f: T => B): DecoupledIO[B] = {
+ val _map_bits = f(bits)
+ val _map = Wire(Decoupled(chiselTypeOf(_map_bits)))
+ _map.bits := _map_bits
+ _map.valid := valid
+ ready := _map.ready
+ _map
+ }
+}
/** This factory adds a decoupled handshaking protocol to a data bundle. */
object Decoupled {
@@ -231,7 +248,6 @@ class QueueIO[T <: Data](
* consumer.io.in <> q.io.deq
* }}}
*/
-@chiselName
class Queue[T <: Data](
val gen: T,
val entries: Int,
@@ -342,7 +358,7 @@ object Queue {
* consumer.io.in <> Queue(producer.io.out, 16)
* }}}
*/
- @chiselName
+ @nowarn("cat=deprecation&msg=TransitName")
def apply[T <: Data](
enq: ReadyValidIO[T],
entries: Int = 2,
diff --git a/src/main/scala/chisel3/util/Reg.scala b/src/main/scala/chisel3/util/Reg.scala
index ddb74dd6..89381c11 100644
--- a/src/main/scala/chisel3/util/Reg.scala
+++ b/src/main/scala/chisel3/util/Reg.scala
@@ -12,7 +12,10 @@ object RegEnable {
* val regWithEnable = RegEnable(nextVal, ena)
* }}}
*/
- def apply[T <: Data](next: T, enable: Bool): T = {
+ def apply[T <: Data](
+ @deprecatedName('next, "Chisel 3.5") next: T,
+ @deprecatedName('enable, "Chisel 3.5") enable: Bool
+ ): T = {
val r = Reg(chiselTypeOf(next))
when(enable) { r := next }
r
@@ -24,7 +27,11 @@ object RegEnable {
* val regWithEnableAndReset = RegEnable(nextVal, 0.U, ena)
* }}}
*/
- def apply[T <: Data](next: T, init: T, enable: Bool): T = {
+ def apply[T <: Data](
+ @deprecatedName('next, "Chisel 3.5") next: T,
+ @deprecatedName('init, "Chisel 3.5") init: T,
+ @deprecatedName('enable, "Chisel 3.5") enable: Bool
+ ): T = {
val r = RegInit(init)
when(enable) { r := next }
r
@@ -43,7 +50,11 @@ object ShiftRegister {
* val regDelayTwo = ShiftRegister(nextVal, 2, ena)
* }}}
*/
- def apply[T <: Data](in: T, n: Int, en: Bool = true.B): T = ShiftRegisters(in, n, en).lastOption.getOrElse(in)
+ def apply[T <: Data](
+ @deprecatedName('in, "Chisel 3.5") in: T,
+ @deprecatedName('n, "Chisel 3.5") n: Int,
+ @deprecatedName('en, "Chisel 3.5") en: Bool = true.B
+ ): T = ShiftRegisters(in, n, en).lastOption.getOrElse(in)
/** Returns the n-cycle delayed version of the input signal with reset initialization.
*
@@ -56,7 +67,12 @@ object ShiftRegister {
* val regDelayTwoReset = ShiftRegister(nextVal, 2, 0.U, ena)
* }}}
*/
- def apply[T <: Data](in: T, n: Int, resetData: T, en: Bool): T =
+ def apply[T <: Data](
+ @deprecatedName('in, "Chisel 3.5") in: T,
+ @deprecatedName('n, "Chisel 3.5") n: Int,
+ @deprecatedName('resetData, "Chisel 3.5") resetData: T,
+ @deprecatedName('en, "Chisel 3.5") en: Bool
+ ): T =
ShiftRegisters(in, n, resetData, en).lastOption.getOrElse(in)
}
@@ -68,7 +84,11 @@ object ShiftRegisters {
* @param n number of cycles to delay
* @param en enable the shift
*/
- def apply[T <: Data](in: T, n: Int, en: Bool = true.B): Seq[T] =
+ def apply[T <: Data](
+ @deprecatedName('in, "Chisel 3.5") in: T,
+ @deprecatedName('n, "Chisel 3.5") n: Int,
+ @deprecatedName('en, "Chisel 3.5") en: Bool = true.B
+ ): Seq[T] =
Seq.iterate(in, n + 1)(util.RegEnable(_, en)).drop(1)
/** Returns delayed input signal registers with reset initialization from 1 to n.
@@ -78,6 +98,11 @@ object ShiftRegisters {
* @param resetData reset value for each register in the shift
* @param en enable the shift
*/
- def apply[T <: Data](in: T, n: Int, resetData: T, en: Bool): Seq[T] =
+ def apply[T <: Data](
+ @deprecatedName('in, "Chisel 3.5") in: T,
+ @deprecatedName('n, "Chisel 3.5") n: Int,
+ @deprecatedName('resetData, "Chisel 3.5") resetData: T,
+ @deprecatedName('en, "Chisel 3.5") en: Bool
+ ): Seq[T] =
Seq.iterate(in, n + 1)(util.RegEnable(_, resetData, en)).drop(1)
}
diff --git a/src/main/scala/chisel3/util/TransitName.scala b/src/main/scala/chisel3/util/TransitName.scala
index cc8f2456..8b509db5 100644
--- a/src/main/scala/chisel3/util/TransitName.scala
+++ b/src/main/scala/chisel3/util/TransitName.scala
@@ -42,6 +42,12 @@ object TransitName {
* @param to the thing that will receive the "good" name
* @return the `from` parameter
*/
+ @deprecated(
+ "Use suggestName or rely on the naming plugin instead of this function: \n" +
+ " val from = {to}\n" +
+ " val from = prefix(prefixYouWant){to}",
+ "Chisel 3.5.4"
+ )
def apply[T <: HasId](from: T, to: HasId): T = {
// To transit a name, we need to hook on both the suggestName and autoSeed mechanisms
from.addSuggestPostnameHook((given_name: String) => { to.suggestName(given_name) })
@@ -55,6 +61,11 @@ object TransitName {
* @param to the thing that will receive the "good" name
* @return the `from` parameter
*/
+ @deprecated(
+ "Use suggestName or rely on the naming plugin instead of this function. Use prefix instead of suffix: \n" +
+ " val from = prefix(prefixYouWant){to}",
+ "Chisel 3.5.4"
+ )
def withSuffix[T <: HasId](suffix: String)(from: T, to: HasId): T = {
// To transit a name, we need to hook on both the suggestName and autoSeed mechanisms
from.addSuggestPostnameHook((given_name: String) => { to.suggestName(given_name + suffix) })
diff --git a/src/main/scala/chisel3/util/Valid.scala b/src/main/scala/chisel3/util/Valid.scala
index eeb2ab68..cb0e166a 100644
--- a/src/main/scala/chisel3/util/Valid.scala
+++ b/src/main/scala/chisel3/util/Valid.scala
@@ -7,6 +7,8 @@ package chisel3.util
import chisel3._
+import scala.annotation.nowarn
+
/** A [[Bundle]] that adds a `valid` bit to some data. This indicates that the user expects a "valid" interface between
* a producer and a consumer. Here, the producer asserts the `valid` bit when data on the `bits` line contains valid
* data. This differs from [[DecoupledIO]] or [[IrrevocableIO]] as there is no `ready` line that the consumer can use
@@ -116,6 +118,7 @@ object Pipe {
* @param latency the number of pipeline stages
* @return $returnType
*/
+ @nowarn("cat=deprecation&msg=TransitName")
def apply[T <: Data](enqValid: Bool, enqBits: T, latency: Int)(implicit compileOptions: CompileOptions): Valid[T] = {
require(latency >= 0, "Pipe latency must be greater than or equal to zero!")
if (latency == 0) {
diff --git a/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala b/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala
index 86973e5b..8c85b6d1 100644
--- a/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala
+++ b/src/main/scala/chisel3/util/experimental/decode/EspressoMinimizer.scala
@@ -87,6 +87,6 @@ object EspressoMinimizer extends Minimizer with LazyLogging {
logger.trace(s"""espresso output table:
|$output
|""".stripMargin)
- TruthTable(readTable(output), table.default)
+ TruthTable.fromEspressoOutput(readTable(output), table.default)
}
}
diff --git a/src/main/scala/chisel3/util/experimental/decode/TruthTable.scala b/src/main/scala/chisel3/util/experimental/decode/TruthTable.scala
index 00fa0f9c..2720e690 100644
--- a/src/main/scala/chisel3/util/experimental/decode/TruthTable.scala
+++ b/src/main/scala/chisel3/util/experimental/decode/TruthTable.scala
@@ -3,6 +3,7 @@
package chisel3.util.experimental.decode
import chisel3.util.BitPat
+import scala.collection.mutable
sealed class TruthTable private (val table: Seq[(BitPat, BitPat)], val default: BitPat, val sort: Boolean) {
def inputWidth = table.head._1.getWidth
@@ -29,40 +30,89 @@ sealed class TruthTable private (val table: Seq[(BitPat, BitPat)], val default:
object TruthTable {
- /** Convert a table and default output into a [[TruthTable]]. */
- def apply(table: Iterable[(BitPat, BitPat)], default: BitPat, sort: Boolean = true): TruthTable = {
+ /** Pad the input signals to equalize all input widths. Pads input signals
+ * to the maximum width found in the table.
+ *
+ * @param table the truth table whose rows will be padded
+ * @return the same truth table but with inputs padded
+ */
+ private def padInputs(table: Iterable[(BitPat, BitPat)]): Iterable[(BitPat, BitPat)] = {
val inputWidth = table.map(_._1.getWidth).max
- require(table.map(_._2.getWidth).toSet.size == 1, "output width not equal.")
- val outputWidth = table.map(_._2.getWidth).head
- val mergedTable = table.map {
- // pad input signals if necessary
+ table.map {
case (in, out) if inputWidth > in.width =>
(BitPat.N(inputWidth - in.width) ## in, out)
case (in, out) => (in, out)
}
- .groupBy(_._1.toString)
- .map {
- case (key, values) =>
- // merge same input inputs.
- values.head._1 -> BitPat(s"b${Seq
- .tabulate(outputWidth) { i =>
- val outputSet = values
- .map(_._2)
- .map(_.rawString)
- .map(_(i))
- .toSet
- .filterNot(_ == '?')
- require(
- outputSet.size != 2,
- s"TruthTable conflict in :\n${values.map { case (i, o) => s"${i.rawString}->${o.rawString}" }.mkString("\n")}"
- )
- outputSet.headOption.getOrElse('?')
- }
- .mkString}")
- }
- .toSeq
+ }
+
+ /** For each duplicated input, collect the outputs into a single Seq.
+ *
+ * @param table the truth table
+ * @return a Seq of tuple of length 2, where the first element is the
+ * input and the second element is a Seq of OR-ed outputs
+ * for the input
+ */
+ private def mergeTableOnInputs(table: Iterable[(BitPat, BitPat)]): Seq[(BitPat, Seq[BitPat])] = {
+ groupByIntoSeq(table)(_._1).map {
+ case (input, mappings) =>
+ input -> mappings.map(_._2)
+ }
+ }
+
+ /** Merge two BitPats by OR-ing the values and masks, and setting the
+ * width to the max width among the two
+ */
+ private def merge(a: BitPat, b: BitPat): BitPat = {
+ new BitPat(a.value | b.value, a.mask | b.mask, a.width.max(b.width))
+ }
+
+ /** Public method for calling with the Espresso decoder format fd
+ *
+ * For Espresso, for each output, a 1 means this product term belongs to the ON-set,
+ * a 0 means this product term has no meaning for the value of this function.
+ * This is the same as the fd (or f) type in espresso.
+ *
+ * @param table the truth table
+ * @param default the default BitPat is made up of a single bit type, either "?", "0" or "1".
+ * A default of "?" sets Espresso to fr-format, while a "0" or "1" sets it to the
+ * fd-format.
+ * @param sort whether to sort the final truth table using BitPat.bitPatOrder
+ * @return a fully built TruthTable
+ */
+ def fromEspressoOutput(table: Iterable[(BitPat, BitPat)], default: BitPat, sort: Boolean = true): TruthTable = {
+ apply_impl(table, default, sort, false)
+ }
+
+ /** Public apply method to TruthTable. Calls apply_impl with the default value true of checkCollisions */
+ def apply(table: Iterable[(BitPat, BitPat)], default: BitPat, sort: Boolean = true): TruthTable = {
+ apply_impl(table, default, sort, true)
+ }
+
+ /** Convert a table and default output into a [[TruthTable]]. */
+ private def apply_impl(
+ table: Iterable[(BitPat, BitPat)],
+ default: BitPat,
+ sort: Boolean,
+ checkCollisions: Boolean
+ ): TruthTable = {
+ val paddedTable = padInputs(table)
+
+ require(table.map(_._2.getWidth).toSet.size == 1, "output width not equal.")
+
+ val mergedTable = mergeTableOnInputs(paddedTable)
+
+ val finalTable: Seq[(BitPat, BitPat)] = mergedTable.map {
+ case (input, outputs) =>
+ val (result, noCollisions) = outputs.tail.foldLeft((outputs.head, checkCollisions)) {
+ case ((acc, ok), o) => (merge(acc, o), ok && acc.overlap(o))
+ }
+ // Throw an error if checkCollisions is true but there are bits with a non-zero overlap.
+ require(!checkCollisions || noCollisions, s"TruthTable conflict on merged row:\n $input -> $outputs")
+ (input, result)
+ }
+
import BitPat.bitPatOrder
- new TruthTable(if (sort) mergedTable.sorted else mergedTable, default, sort)
+ new TruthTable(if (sort) finalTable.sorted else finalTable, default, sort)
}
/** Parse TruthTable from its string representation. */
@@ -140,4 +190,15 @@ object TruthTable {
bitPat(tables.flatMap { case (table, indexes) => table.default.rawString.zip(indexes) })
)
}
+
+ /** Similar to Seq.groupBy except that it preserves ordering of elements within each group */
+ private def groupByIntoSeq[A, K](xs: Iterable[A])(f: A => K): Seq[(K, Seq[A])] = {
+ val map = mutable.LinkedHashMap.empty[K, mutable.ListBuffer[A]]
+ for (x <- xs) {
+ val key = f(x)
+ val l = map.getOrElseUpdate(key, mutable.ListBuffer.empty[A])
+ l += x
+ }
+ map.view.map({ case (k, vs) => k -> vs.toList }).toList
+ }
}
diff --git a/src/test/scala/chiselTests/AutoClonetypeSpec.scala b/src/test/scala/chiselTests/AutoClonetypeSpec.scala
index 2ab4c800..5d2cd496 100644
--- a/src/test/scala/chiselTests/AutoClonetypeSpec.scala
+++ b/src/test/scala/chiselTests/AutoClonetypeSpec.scala
@@ -381,4 +381,23 @@ class AutoClonetypeSpec extends ChiselFlatSpec with Utils {
}
elaborate(new MyModule)
}
+
+ it should "support Bundles with vararg arguments" in {
+ // Without the fix, this doesn't even compile
+ // Extra parameter lists to make this a complex test case
+ class VarArgsBundle(x: Int)(y: Int, widths: Int*) extends Bundle {
+ def mkField(idx: Int): Option[UInt] =
+ (x +: y +: widths).lift(idx).map(w => UInt(w.W))
+ val foo = mkField(0)
+ val bar = mkField(1)
+ val fizz = mkField(2)
+ val buzz = mkField(3)
+ }
+ class MyModule extends Module {
+ val in = IO(Input(new VarArgsBundle(1)(2, 3, 4)))
+ val out = IO(Output(new VarArgsBundle(1)(2, 3, 4)))
+ out := in
+ }
+ elaborate(new MyModule)
+ }
}
diff --git a/src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala b/src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala
index 70dcda48..1e199297 100644
--- a/src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala
+++ b/src/test/scala/chiselTests/CompatibilityInteroperabilitySpec.scala
@@ -351,4 +351,43 @@ class CompatibilityInteroperabilitySpec extends ChiselFlatSpec {
compile(new Top(true))
compile(new Top(false))
}
+
+ "A unidirectional but flipped Bundle with something close to NotStrict compileOptions, but not exactly" should "bulk connect in import chisel3._ code correctly" in {
+ object Compat {
+ import Chisel.{defaultCompileOptions => _, _}
+ // arbitrary thing to make this *not* exactly NotStrict
+ implicit val defaultCompileOptions = new chisel3.ExplicitCompileOptions.CompileOptionsClass(
+ connectFieldsMustMatch = false,
+ declaredTypeMustBeUnbound = false,
+ dontTryConnectionsSwapped = false,
+ dontAssumeDirectionality = false,
+ checkSynthesizable = false,
+ explicitInvalidate = false,
+ inferModuleReset = true // different from NotStrict, to ensure case class equivalence to NotStrict is false
+ ) {
+ override def emitStrictConnects = false
+ }
+
+ class MyBundle(extraFlip: Boolean) extends Bundle {
+ private def maybeFlip[T <: Data](t: T): T = if (extraFlip) t.flip else t
+ val foo = maybeFlip(new Bundle {
+ val bar = UInt(INPUT, width = 8)
+ })
+ }
+ }
+ import chisel3._
+ import Compat.{defaultCompileOptions => _, _}
+ class Top(extraFlip: Boolean) extends RawModule {
+ val port = IO(new MyBundle(extraFlip))
+ val wire = Wire(new MyBundle(extraFlip))
+ port <> DontCare
+ wire <> DontCare
+ port <> wire
+ wire <> port
+ port.foo <> wire.foo
+ wire.foo <> port.foo
+ }
+ compile(new Top(true))
+ compile(new Top(false))
+ }
}
diff --git a/src/test/scala/chiselTests/CompileOptionsTest.scala b/src/test/scala/chiselTests/CompileOptionsTest.scala
index 3ec59954..b39d8ee3 100644
--- a/src/test/scala/chiselTests/CompileOptionsTest.scala
+++ b/src/test/scala/chiselTests/CompileOptionsTest.scala
@@ -163,4 +163,32 @@ class CompileOptionsSpec extends ChiselFlatSpec with Utils {
}
}
+ "Strict.copy()" should "be equivalent in all CompileOptions traits" in {
+ import chisel3.ExplicitCompileOptions.Strict
+ val copiedCompileOptions = Strict.copy()
+ assert(copiedCompileOptions.connectFieldsMustMatch == Strict.connectFieldsMustMatch)
+ assert(copiedCompileOptions.declaredTypeMustBeUnbound == Strict.declaredTypeMustBeUnbound)
+ assert(copiedCompileOptions.dontTryConnectionsSwapped == Strict.dontTryConnectionsSwapped)
+ assert(copiedCompileOptions.dontAssumeDirectionality == Strict.dontAssumeDirectionality)
+ assert(copiedCompileOptions.checkSynthesizable == Strict.checkSynthesizable)
+ assert(copiedCompileOptions.explicitInvalidate == Strict.explicitInvalidate)
+ assert(copiedCompileOptions.inferModuleReset == Strict.inferModuleReset)
+ assert(copiedCompileOptions.migrateInferModuleReset == Strict.migrateInferModuleReset)
+ assert(copiedCompileOptions.emitStrictConnects == Strict.emitStrictConnects)
+ }
+
+ "NotStrict.copy()" should "be equivalent in all CompileOptions traits" in {
+ import chisel3.ExplicitCompileOptions.NotStrict
+ val copiedCompileOptions = NotStrict.copy()
+ assert(copiedCompileOptions.connectFieldsMustMatch == NotStrict.connectFieldsMustMatch)
+ assert(copiedCompileOptions.declaredTypeMustBeUnbound == NotStrict.declaredTypeMustBeUnbound)
+ assert(copiedCompileOptions.dontTryConnectionsSwapped == NotStrict.dontTryConnectionsSwapped)
+ assert(copiedCompileOptions.dontAssumeDirectionality == NotStrict.dontAssumeDirectionality)
+ assert(copiedCompileOptions.checkSynthesizable == NotStrict.checkSynthesizable)
+ assert(copiedCompileOptions.explicitInvalidate == NotStrict.explicitInvalidate)
+ assert(copiedCompileOptions.inferModuleReset == NotStrict.inferModuleReset)
+ assert(copiedCompileOptions.migrateInferModuleReset == NotStrict.migrateInferModuleReset)
+ assert(copiedCompileOptions.emitStrictConnects == NotStrict.emitStrictConnects)
+ }
+
}
diff --git a/src/test/scala/chiselTests/DecoupledSpec.scala b/src/test/scala/chiselTests/DecoupledSpec.scala
index 2d305f4a..69d74aab 100644
--- a/src/test/scala/chiselTests/DecoupledSpec.scala
+++ b/src/test/scala/chiselTests/DecoupledSpec.scala
@@ -17,4 +17,95 @@ class DecoupledSpec extends ChiselFlatSpec {
assert(io.asUInt.widthOption.get === 4)
})
}
+
+ "Decoupled.map" should "apply a function to a wrapped Data" in {
+ val chirrtl = ChiselStage
+ .emitChirrtl(new Module {
+ val enq = IO(Flipped(Decoupled(UInt(8.W))))
+ val deq = IO(Decoupled(UInt(8.W)))
+ deq <> enq.map(_ + 1.U)
+ })
+
+ // Check for data assignment
+ chirrtl should include("""node _deq_map_bits_T = add(enq.bits, UInt<1>("h1")""")
+ chirrtl should include("""node _deq_map_bits = tail(_deq_map_bits_T, 1)""")
+ chirrtl should include("""_deq_map.bits <= _deq_map_bits""")
+ chirrtl should include("""deq <= _deq_map""")
+
+ // Check for back-pressure (ready signal is driven in the opposite direction of bits + valid)
+ chirrtl should include("""enq.ready <= _deq_map.ready""")
+ }
+
+ "Decoupled.map" should "apply a function to a wrapped Bundle" in {
+ class TestBundle extends Bundle {
+ val foo = UInt(8.W)
+ val bar = UInt(8.W)
+ val fizz = Bool()
+ val buzz = Bool()
+ }
+
+ // Add one to foo, subtract one from bar, set fizz to false and buzz to true
+ def func(t: TestBundle): TestBundle = {
+ val res = Wire(new TestBundle)
+
+ res.foo := t.foo + 1.U
+ res.bar := t.bar - 1.U
+ res.fizz := false.B
+ res.buzz := true.B
+
+ res
+ }
+
+ val chirrtl = ChiselStage
+ .emitChirrtl(new Module {
+ val enq = IO(Flipped(Decoupled(new TestBundle)))
+ val deq = IO(Decoupled(new TestBundle))
+ deq <> enq.map(func)
+ })
+
+ // Check for data assignment
+ chirrtl should include("""wire _deq_map_bits : { foo : UInt<8>, bar : UInt<8>, fizz : UInt<1>, buzz : UInt<1>}""")
+
+ chirrtl should include("""node _deq_map_bits_res_foo_T = add(enq.bits.foo, UInt<1>("h1")""")
+ chirrtl should include("""node _deq_map_bits_res_foo_T_1 = tail(_deq_map_bits_res_foo_T, 1)""")
+ chirrtl should include("""_deq_map_bits.foo <= _deq_map_bits_res_foo_T_1""")
+
+ chirrtl should include("""node _deq_map_bits_res_bar_T = sub(enq.bits.bar, UInt<1>("h1")""")
+ chirrtl should include("""node _deq_map_bits_res_bar_T_1 = tail(_deq_map_bits_res_bar_T, 1)""")
+ chirrtl should include("""_deq_map_bits.bar <= _deq_map_bits_res_bar_T_1""")
+
+ chirrtl should include("""_deq_map_bits.fizz <= UInt<1>("h0")""")
+ chirrtl should include("""_deq_map_bits.buzz <= UInt<1>("h1")""")
+
+ chirrtl should include("""_deq_map.bits <= _deq_map_bits""")
+ chirrtl should include("""deq <= _deq_map""")
+
+ // Check for back-pressure (ready signal is driven in the opposite direction of bits + valid)
+ chirrtl should include("""enq.ready <= _deq_map.ready""")
+ }
+
+ "Decoupled.map" should "apply a function to a wrapped Bundle and return a different typed DecoupledIO" in {
+ class TestBundle extends Bundle {
+ val foo = UInt(8.W)
+ val bar = UInt(8.W)
+ }
+
+ val chirrtl = ChiselStage
+ .emitChirrtl(new Module {
+ val enq = IO(Flipped(Decoupled(new TestBundle)))
+ val deq = IO(Decoupled(UInt(8.W)))
+ deq <> enq.map(bundle => bundle.foo & bundle.bar)
+ })
+
+ // Check that the _map wire wraps a UInt and not a TestBundle
+ chirrtl should include("""wire _deq_map : { flip ready : UInt<1>, valid : UInt<1>, bits : UInt<8>}""")
+
+ // Check for data assignment
+ chirrtl should include("""node _deq_map_bits = and(enq.bits.foo, enq.bits.bar)""")
+ chirrtl should include("""_deq_map.bits <= _deq_map_bits""")
+ chirrtl should include("""deq <= _deq_map""")
+
+ // Check for back-pressure (ready signal is driven in the opposite direction of bits + valid)
+ chirrtl should include("""enq.ready <= _deq_map.ready""")
+ }
}
diff --git a/src/test/scala/chiselTests/ExtModule.scala b/src/test/scala/chiselTests/ExtModule.scala
index 1dbd7447..b5a8ff7c 100644
--- a/src/test/scala/chiselTests/ExtModule.scala
+++ b/src/test/scala/chiselTests/ExtModule.scala
@@ -59,6 +59,35 @@ class MultiExtModuleTester extends BasicTester {
stop()
}
+class ExtModuleWithSuggestName extends ExtModule {
+ val in = IO(Input(UInt(8.W)))
+ in.suggestName("foo")
+ val out = IO(Output(UInt(8.W)))
+}
+
+class ExtModuleWithSuggestNameTester extends Module {
+ val in = IO(Input(UInt(8.W)))
+ val out = IO(Output(UInt(8.W)))
+ val inst = Module(new ExtModuleWithSuggestName)
+ inst.in := in
+ out := inst.out
+}
+
+class SimpleIOBundle extends Bundle {
+ val in = Input(UInt(8.W))
+ val out = Output(UInt(8.W))
+}
+
+class ExtModuleWithFlatIO extends ExtModule {
+ val badIO = FlatIO(new SimpleIOBundle)
+}
+
+class ExtModuleWithFlatIOTester extends Module {
+ val io = IO(new SimpleIOBundle)
+ val inst = Module(new ExtModuleWithFlatIO)
+ io <> inst.badIO
+}
+
class ExtModuleSpec extends ChiselFlatSpec {
"A ExtModule inverter" should "work" in {
assertTesterPasses({ new ExtModuleTester }, Seq("/chisel3/BlackBoxTest.v"), TesterDriver.verilatorOnly)
@@ -73,4 +102,19 @@ class ExtModuleSpec extends ChiselFlatSpec {
assert(DataMirror.modulePorts(m) == Seq("in" -> m.in, "out" -> m.out))
})
}
+
+ behavior.of("ExtModule")
+
+ it should "work with .suggestName (aka it should not require reflection for naming)" in {
+ val chirrtl = ChiselStage.emitChirrtl(new ExtModuleWithSuggestNameTester)
+ chirrtl should include("input foo : UInt<8>")
+ chirrtl should include("inst.foo <= in")
+ }
+
+ it should "work with FlatIO" in {
+ val chirrtl = ChiselStage.emitChirrtl(new ExtModuleWithFlatIOTester)
+ chirrtl should include("io.out <= inst.out")
+ chirrtl should include("inst.in <= io.in")
+ chirrtl shouldNot include("badIO")
+ }
}
diff --git a/src/test/scala/chiselTests/InstanceNameSpec.scala b/src/test/scala/chiselTests/InstanceNameSpec.scala
index 7eaf3106..cc5980f4 100644
--- a/src/test/scala/chiselTests/InstanceNameSpec.scala
+++ b/src/test/scala/chiselTests/InstanceNameSpec.scala
@@ -22,28 +22,36 @@ class InstanceNameModule extends Module {
io.bar := io.foo + x
}
-class InstanceNameSpec extends ChiselFlatSpec {
+class InstanceNameSpec extends ChiselFlatSpec with Utils {
behavior.of("instanceName")
val moduleName = "InstanceNameModule"
var m: InstanceNameModule = _
ChiselStage.elaborate { m = new InstanceNameModule; m }
+ val deprecationMsg = "Accessing the .instanceName or .toTarget of non-hardware Data is deprecated"
+
it should "work with module IO" in {
val io = m.io.pathName
assert(io == moduleName + ".io")
}
- it should "work with internal vals" in {
+ it should "work for literals" in {
val x = m.x.pathName
- val y = m.y.pathName
- val z = m.z.pathName
assert(x == moduleName + ".UInt<2>(\"h03\")")
+ }
+
+ it should "work with non-hardware values (but be deprecated)" in {
+ val (ylog, y) = grabLog(m.y.pathName)
+ val (zlog, z) = grabLog(m.z.pathName)
+ ylog should include(deprecationMsg)
assert(y == moduleName + ".y")
+ zlog should include(deprecationMsg)
assert(z == moduleName + ".z")
}
- it should "work with bundle elements" in {
- val foo = m.z.foo.pathName
+ it should "work with non-hardware bundle elements (but be deprecated)" in {
+ val (log, foo) = grabLog(m.z.foo.pathName)
+ log should include(deprecationMsg)
assert(foo == moduleName + ".z.foo")
}
diff --git a/src/test/scala/chiselTests/MigrateCompileOptionsSpec.scala b/src/test/scala/chiselTests/MigrateCompileOptionsSpec.scala
new file mode 100644
index 00000000..091f7f28
--- /dev/null
+++ b/src/test/scala/chiselTests/MigrateCompileOptionsSpec.scala
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: Apache-2.0
+
+package chiselTests
+
+import chisel3.stage.ChiselStage
+import chisel3.ImplicitInvalidate
+import chisel3.ExplicitCompileOptions
+
+import org.scalatestplus.scalacheck.ScalaCheckDrivenPropertyChecks
+
+object MigrationExamples {
+ object InferResets {
+ import Chisel.{defaultCompileOptions => _, _}
+ import chisel3.RequireSyncReset
+ implicit val migrateIR = new chisel3.CompileOptions {
+ val connectFieldsMustMatch = false
+ val declaredTypeMustBeUnbound = false
+ val dontTryConnectionsSwapped = false
+ val dontAssumeDirectionality = false
+ val checkSynthesizable = false
+ val explicitInvalidate = false
+ val inferModuleReset = false
+
+ override val migrateInferModuleReset = true
+ }
+
+ class Foo extends Module {
+ val io = new Bundle {}
+ }
+ class FooWithRequireSyncReset extends Module with RequireSyncReset {
+ val io = new Bundle {}
+ }
+ }
+ object ExplicitInvalidate {
+ import chisel3.ImplicitInvalidate
+ val migrateEI = new chisel3.CompileOptions {
+ val connectFieldsMustMatch = false
+ val declaredTypeMustBeUnbound = false
+ val dontTryConnectionsSwapped = false
+ val dontAssumeDirectionality = false
+ val checkSynthesizable = false
+ val explicitInvalidate = true
+ val inferModuleReset = false
+ }
+ object ChiselChildren {
+ import Chisel.{defaultCompileOptions => _, _}
+ implicit val options = migrateEI
+ class Foo extends Module {
+ val io = new Bundle {
+ val out = Output(UInt(width = 3))
+ }
+ }
+ class FooWithImplicitInvalidate extends Module with ImplicitInvalidate {
+ val io = new Bundle {
+ val out = Output(UInt(width = 3))
+ }
+ }
+ class FooWire extends Module {
+ val io = new Bundle {}
+ val wire = Wire(Bool())
+ }
+ class FooWireWithImplicitInvalidate extends Module with ImplicitInvalidate {
+ val io = new Bundle {}
+ val wire = Wire(Bool())
+ }
+ }
+ object chisel3Children {
+ import chisel3._
+ class Foo extends Module {
+ val in = IO(chisel3.Input(UInt(3.W)))
+ }
+ }
+ object ChiselParents {
+ import Chisel.{defaultCompileOptions => _, _}
+ implicit val options = migrateEI
+
+ class FooParent extends Module {
+ val io = new Bundle {}
+ val i = Module(new chisel3Children.Foo)
+ }
+ class FooParentWithImplicitInvalidate extends Module with ImplicitInvalidate {
+ val io = new Bundle {}
+ val i = Module(new chisel3Children.Foo)
+ }
+ }
+ }
+}
+
+class MigrateCompileOptionsSpec extends ChiselFunSpec with Utils {
+ import Chisel.{defaultCompileOptions => _, _}
+ import chisel3.RequireSyncReset
+
+ describe("(0): Migrating infer resets") {
+ import MigrationExamples.InferResets._
+ it("(0.a): Error if migrating, but not extended RequireSyncReset") {
+ intercept[Exception] { ChiselStage.elaborate(new Foo) }
+ }
+ it("(0.b): Not error if migrating, and you mix with RequireSyncReset") {
+ ChiselStage.elaborate(new FooWithRequireSyncReset)
+ }
+ }
+
+ describe("(1): Migrating explicit invalidate") {
+ import MigrationExamples.ExplicitInvalidate._
+
+ it("(1.a): error if migrating module input, but not extending ImplicitInvalidate") {
+ intercept[_root_.firrtl.passes.CheckInitialization.RefNotInitializedException] {
+ ChiselStage.emitVerilog(new ChiselChildren.Foo)
+ }
+ }
+ it("(1.b): succeed if migrating module input with extending ImplicitInvalidate") {
+ ChiselStage.emitVerilog(new ChiselChildren.FooWithImplicitInvalidate)
+ }
+
+ it("(1.c): error if migrating instance output, but not extending ImplicitInvalidate") {
+ intercept[_root_.firrtl.passes.CheckInitialization.RefNotInitializedException] {
+ ChiselStage.emitVerilog(new ChiselParents.FooParent)
+ }
+ }
+ it("(1.d): succeed if migrating instance output with extending ImplicitInvalidate") {
+ ChiselStage.emitVerilog(new ChiselParents.FooParentWithImplicitInvalidate)
+ }
+
+ it("(1.e): error if migrating wire declaration, but not extending ImplicitInvalidate") {
+ intercept[_root_.firrtl.passes.CheckInitialization.RefNotInitializedException] {
+ ChiselStage.emitVerilog(new ChiselChildren.FooWire)
+ }
+ }
+ it("(1.f): succeed if migrating wire declaration with extending ImplicitInvalidate") {
+ ChiselStage.emitVerilog(new ChiselChildren.FooWireWithImplicitInvalidate)
+ }
+ }
+}
diff --git a/src/test/scala/chiselTests/NamingAnnotationTest.scala b/src/test/scala/chiselTests/NamingAnnotationTest.scala
index ded321cd..a3f39c51 100644
--- a/src/test/scala/chiselTests/NamingAnnotationTest.scala
+++ b/src/test/scala/chiselTests/NamingAnnotationTest.scala
@@ -4,12 +4,13 @@ package chiselTests
import chisel3._
import chisel3.experimental.chiselName
+import chisel3.experimental.AffectsChiselPrefix
import chisel3.internal.InstanceId
import chisel3.stage.ChiselStage
import scala.collection.mutable.ListBuffer
-trait NamedModuleTester extends Module {
+trait NamedModuleTester extends Module with AffectsChiselPrefix {
val expectedNameMap = ListBuffer[(InstanceId, String)]()
val expectedModuleNameMap = ListBuffer[(Module, String)]()
@@ -48,25 +49,20 @@ trait NamedModuleTester extends Module {
failures.toList
}
}
-@chiselName
-class OuterNamedNonModule {
+class OuterNamedNonModule extends AffectsChiselPrefix {
val value = Wire(Bool())
}
-@chiselName
-class NonModule {
+class NonModule extends AffectsChiselPrefix {
val value = Wire(Bool())
- @chiselName
- class InnerNamedNonModule {
+ class InnerNamedNonModule extends AffectsChiselPrefix {
val value = Wire(Bool())
}
val inner = new InnerNamedNonModule
val outer = new OuterNamedNonModule
}
-@chiselName
class NamedModule extends NamedModuleTester {
- @chiselName
def FunctionMockupInner(): UInt = {
val my2A = 1.U
val my2B = expectName(my2A +& 2.U, "test_myNested_my2B")
@@ -74,7 +70,6 @@ class NamedModule extends NamedModuleTester {
my2C
}
- @chiselName
def FunctionMockup(): UInt = {
val myNested = expectName(FunctionMockupInner(), "test_myNested")
val myA = expectName(1.U + myNested, "test_myA")
@@ -123,11 +118,9 @@ class NamedModule extends NamedModuleTester {
NoReturnFunction()
}
-@chiselName
class NameCollisionModule extends NamedModuleTester {
- @chiselName
- def repeatedCalls(id: Int): UInt = {
- val test = expectName(1.U + 3.U, s"test_$id") // should disambiguate by invocation order
+ def repeatedCalls(name: String): UInt = {
+ val test = expectName(1.U + 3.U, s"${name}_test") // should disambiguate by invocation order
test + 2.U
}
@@ -135,8 +128,8 @@ class NameCollisionModule extends NamedModuleTester {
def innerNamedFunction() {
// ... but not this inner function
def innerUnnamedFunction() {
- val a = repeatedCalls(1)
- val b = repeatedCalls(2)
+ val a = repeatedCalls("a")
+ val b = repeatedCalls("b")
}
innerUnnamedFunction()
@@ -212,19 +205,17 @@ class NoChiselNamePrefixTester extends NamedModuleTester {
val a = expectName(1.U +& 2.U, "a")
}
val inst = new NoChiselNamePrefixClass
- @chiselName
class NormalClass {
val b = 1.U +& 2.U
}
- val foo = new NormalClass
+ val foo = new NormalClass with AffectsChiselPrefix
expectName(foo.b, "foo_b")
val bar = new NormalClass with chisel3.experimental.NoChiselNamePrefix
expectName(bar.b, "b")
// Check that we're not matching by name but actual type
trait NoChiselNamePrefix
- @chiselName
- class FakeNoChiselNamePrefix extends NoChiselNamePrefix {
+ class FakeNoChiselNamePrefix extends NoChiselNamePrefix with AffectsChiselPrefix {
val c = 1.U +& 2.U
}
val fizz = new FakeNoChiselNamePrefix
diff --git a/src/test/scala/chiselTests/NewAnnotationsSpec.scala b/src/test/scala/chiselTests/NewAnnotationsSpec.scala
new file mode 100644
index 00000000..38e1c1d9
--- /dev/null
+++ b/src/test/scala/chiselTests/NewAnnotationsSpec.scala
@@ -0,0 +1,72 @@
+package chiselTests
+import chisel3._
+import chisel3.experimental.{annotate, ChiselMultiAnnotation}
+import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage}
+import firrtl.stage.FirrtlCircuitAnnotation
+import org.scalatest.freespec.AnyFreeSpec
+import org.scalatest.matchers.should.Matchers
+import firrtl.transforms.NoDedupAnnotation
+import firrtl.transforms.DontTouchAnnotation
+
+class NewAnnotationsSpec extends AnyFreeSpec with Matchers {
+
+ class MuchUsedModule extends Module {
+ val io = IO(new Bundle {
+ val in = Input(UInt(16.W))
+ val out = Output(UInt(16.W))
+ })
+ io.out := io.in +% 1.U
+ }
+
+ class UsesMuchUsedModule extends Module {
+ val io = IO(new Bundle {
+ val in = Input(UInt(16.W))
+ val out = Output(UInt(16.W))
+ })
+
+ val mod0 = Module(new MuchUsedModule)
+ val mod1 = Module(new MuchUsedModule)
+ val mod2 = Module(new MuchUsedModule)
+ val mod3 = Module(new MuchUsedModule)
+
+ mod0.io.in := io.in
+ mod1.io.in := mod0.io.out
+ mod2.io.in := mod1.io.out
+ mod3.io.in := mod2.io.out
+ io.out := mod3.io.out
+
+ // Give two annotations as single element of the seq - ensures previous API works by wrapping into a seq.
+ annotate(new ChiselMultiAnnotation { def toFirrtl = Seq(new NoDedupAnnotation(mod2.toNamed)) })
+ annotate(new ChiselMultiAnnotation { def toFirrtl = Seq(new NoDedupAnnotation(mod3.toNamed)) })
+
+ // Pass multiple annotations in the same seq - should get emitted out correctly.
+ annotate(new ChiselMultiAnnotation {
+ def toFirrtl =
+ Seq(new DontTouchAnnotation(mod1.io.in.toNamed), new DontTouchAnnotation(mod1.io.out.toNamed))
+ })
+ }
+
+ val stage = new ChiselStage
+ "Ensure all annotations continue to be passed / digested correctly with the new API" - {
+ "NoDedup and DontTouch work as expected" in {
+ val dutAnnos = stage
+ .execute(
+ Array("-X", "low", "--target-dir", "test_run_dir"),
+ Seq(ChiselGeneratorAnnotation(() => new UsesMuchUsedModule))
+ )
+
+ val dontTouchAnnos = dutAnnos.collect { case DontTouchAnnotation(target) => target.serialize }
+ val noDedupAnnos = dutAnnos.collect { case NoDedupAnnotation(target) => target.serialize }
+ require(dontTouchAnnos.size == 2, s"Exactly two DontTouch Annotations expected but got $dontTouchAnnos ")
+ require(noDedupAnnos.size == 2, s"Exactly two NoDedup Annotations expected but got $noDedupAnnos ")
+ val dontTouchAnnosCombined = dontTouchAnnos.mkString(",")
+ val noDedupAnnosCombined = noDedupAnnos.mkString(",")
+
+ noDedupAnnosCombined should include("~UsesMuchUsedModule|MuchUsedModule_2")
+ noDedupAnnosCombined should include("~UsesMuchUsedModule|MuchUsedModule_3")
+ dontTouchAnnosCombined should include("~UsesMuchUsedModule|UsesMuchUsedModule/mod1:MuchUsedModule>io_out")
+ dontTouchAnnosCombined should include("~UsesMuchUsedModule|UsesMuchUsedModule/mod1:MuchUsedModule>io_in")
+
+ }
+ }
+}
diff --git a/src/test/scala/chiselTests/PrintableSpec.scala b/src/test/scala/chiselTests/PrintableSpec.scala
index 7d584cea..8039918d 100644
--- a/src/test/scala/chiselTests/PrintableSpec.scala
+++ b/src/test/scala/chiselTests/PrintableSpec.scala
@@ -9,7 +9,8 @@ import chisel3.testers.BasicTester
import firrtl.annotations.{ReferenceTarget, SingleTargetAnnotation}
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
-
+import chisel3.util._
+import org.scalactic.source.Position
import java.io.File
/** Dummy [[printf]] annotation.
@@ -32,7 +33,7 @@ object PrintfAnnotation {
}
/* Printable Tests */
-class PrintableSpec extends AnyFlatSpec with Matchers {
+class PrintableSpec extends AnyFlatSpec with Matchers with Utils {
// This regex is brittle, it specifically finds the clock and enable signals followed by commas
private val PrintfRegex = """\s*printf\(\w+, [^,]+,(.*)\).*""".r
private val StringRegex = """([^"]*)"(.*?)"(.*)""".r
@@ -47,7 +48,6 @@ class PrintableSpec extends AnyFlatSpec with Matchers {
case _ => fail(s"Regex to process Printf should work on $str!")
}
}
-
firrtl.split("\n").collect {
case PrintfRegex(matched) =>
val (str, args) = processBody(matched)
@@ -55,26 +55,34 @@ class PrintableSpec extends AnyFlatSpec with Matchers {
}
}
+ // Generates firrtl, gets Printfs
+ // Calls fail() if failed match; else calls the partial function which could have its own check
+ private def generateAndCheck(gen: => RawModule)(check: PartialFunction[Seq[Printf], Unit])(implicit pos: Position) = {
+ val firrtl = ChiselStage.emitChirrtl(gen)
+ val printfs = getPrintfs(firrtl)
+ if (!check.isDefinedAt(printfs)) {
+ fail()
+ } else {
+ check(printfs)
+ }
+ }
+
behavior.of("Printable & Custom Interpolator")
it should "pass exact strings through" in {
class MyModule extends BasicTester {
printf(p"An exact string")
}
- val firrtl = ChiselStage.emitChirrtl(new MyModule)
- getPrintfs(firrtl) match {
+ generateAndCheck(new MyModule) {
case Seq(Printf("An exact string", Seq())) =>
- case e => fail()
}
}
it should "handle Printable and String concatination" in {
class MyModule extends BasicTester {
printf(p"First " + PString("Second ") + "Third")
}
- val firrtl = ChiselStage.emitChirrtl(new MyModule)
- getPrintfs(firrtl) match {
+ generateAndCheck(new MyModule) {
case Seq(Printf("First Second Third", Seq())) =>
- case e => fail()
}
}
it should "call toString on non-Printable objects" in {
@@ -82,10 +90,8 @@ class PrintableSpec extends AnyFlatSpec with Matchers {
val myInt = 1234
printf(p"myInt = $myInt")
}
- val firrtl = ChiselStage.emitChirrtl(new MyModule)
- getPrintfs(firrtl) match {
+ generateAndCheck(new MyModule) {
case Seq(Printf("myInt = 1234", Seq())) =>
- case e => fail()
}
}
it should "generate proper printf for simple Decimal printing" in {
@@ -93,41 +99,33 @@ class PrintableSpec extends AnyFlatSpec with Matchers {
val myWire = WireDefault(1234.U)
printf(p"myWire = ${Decimal(myWire)}")
}
- val firrtl = ChiselStage.emitChirrtl(new MyModule)
- getPrintfs(firrtl) match {
+ generateAndCheck(new MyModule) {
case Seq(Printf("myWire = %d", Seq("myWire"))) =>
- case e => fail()
}
}
it should "handle printing literals" in {
class MyModule extends BasicTester {
printf(Decimal(10.U(32.W)))
}
- val firrtl = ChiselStage.emitChirrtl(new MyModule)
- getPrintfs(firrtl) match {
+ generateAndCheck(new MyModule) {
case Seq(Printf("%d", Seq(lit))) =>
assert(lit contains "UInt<32>")
- case e => fail()
}
}
it should "correctly escape percent" in {
class MyModule extends BasicTester {
printf(p"%")
}
- val firrtl = ChiselStage.emitChirrtl(new MyModule)
- getPrintfs(firrtl) match {
+ generateAndCheck(new MyModule) {
case Seq(Printf("%%", Seq())) =>
- case e => fail()
}
}
it should "correctly emit tab" in {
class MyModule extends BasicTester {
printf(p"\t")
}
- val firrtl = ChiselStage.emitChirrtl(new MyModule)
- getPrintfs(firrtl) match {
+ generateAndCheck(new MyModule) {
case Seq(Printf("\\t", Seq())) =>
- case e => fail()
}
}
it should "support names of circuit elements including submodule IO" in {
@@ -149,10 +147,8 @@ class PrintableSpec extends AnyFlatSpec with Matchers {
printf(p"${FullName(myWire.foo)}")
printf(p"${FullName(myInst.io.fizz)}")
}
- val firrtl = ChiselStage.emitChirrtl(new MyModule)
- getPrintfs(firrtl) match {
+ generateAndCheck(new MyModule) {
case Seq(Printf("foo", Seq()), Printf("myWire.foo", Seq()), Printf("myInst.io.fizz", Seq())) =>
- case e => fail()
}
}
it should "handle printing ports of submodules" in {
@@ -165,10 +161,8 @@ class PrintableSpec extends AnyFlatSpec with Matchers {
val myInst = Module(new MySubModule)
printf(p"${myInst.io.fizz}")
}
- val firrtl = ChiselStage.emitChirrtl(new MyModule)
- getPrintfs(firrtl) match {
+ generateAndCheck(new MyModule) {
case Seq(Printf("%d", Seq("myInst.io.fizz"))) =>
- case e => fail()
}
}
it should "print UInts and SInts as Decimal by default" in {
@@ -177,10 +171,8 @@ class PrintableSpec extends AnyFlatSpec with Matchers {
val mySInt = WireDefault(-1.S)
printf(p"$myUInt & $mySInt")
}
- val firrtl = ChiselStage.emitChirrtl(new MyModule)
- getPrintfs(firrtl) match {
+ generateAndCheck(new MyModule) {
case Seq(Printf("%d & %d", Seq("myUInt", "mySInt"))) =>
- case e => fail()
}
}
it should "print Vecs like Scala Seqs by default" in {
@@ -189,10 +181,8 @@ class PrintableSpec extends AnyFlatSpec with Matchers {
myVec.foreach(_ := 0.U)
printf(p"$myVec")
}
- val firrtl = ChiselStage.emitChirrtl(new MyModule)
- getPrintfs(firrtl) match {
+ generateAndCheck(new MyModule) {
case Seq(Printf("Vec(%d, %d, %d, %d)", Seq("myVec[0]", "myVec[1]", "myVec[2]", "myVec[3]"))) =>
- case e => fail()
}
}
it should "print Bundles like Scala Maps by default" in {
@@ -205,10 +195,8 @@ class PrintableSpec extends AnyFlatSpec with Matchers {
myBun.bar := 0.U
printf(p"$myBun")
}
- val firrtl = ChiselStage.emitChirrtl(new MyModule)
- getPrintfs(firrtl) match {
+ generateAndCheck(new MyModule) {
case Seq(Printf("AnonymousBundle(foo -> %d, bar -> %d)", Seq("myBun.foo", "myBun.bar"))) =>
- case e => fail()
}
}
it should "get emitted with a name and annotated" in {
@@ -261,4 +249,145 @@ class PrintableSpec extends AnyFlatSpec with Matchers {
"""printf(clock, UInt<1>("h1"), "adieu AnonymousBundle(foo -> %d, bar -> %d)", myBun.foo, myBun.bar) : farewell"""
)
}
+
+ // Unit tests for cf
+ it should "print regular scala variables with cf format specifier" in {
+
+ class MyModule extends BasicTester {
+ val f1 = 20.4517
+ val i1 = 10
+ val str1 = "String!"
+ printf(
+ cf"F1 = $f1 D1 = $i1 F1 formatted = $f1%2.2f str1 = $str1%s i1_str = $i1%s i1_hex=$i1%x"
+ )
+
+ }
+
+ generateAndCheck(new MyModule) {
+ case Seq(Printf("F1 = 20.4517 D1 = 10 F1 formatted = 20.45 str1 = String! i1_str = 10 i1_hex=a", Seq())) =>
+ }
+ }
+
+ it should "print chisel bits with cf format specifier" in {
+
+ class MyBundle extends Bundle {
+ val foo = UInt(32.W)
+ val bar = UInt(32.W)
+ override def toPrintable: Printable = {
+ cf"Bundle : " +
+ cf"Foo : $foo%x Bar : $bar%x"
+ }
+ }
+ class MyModule extends BasicTester {
+ val b1 = 10.U
+ val w1 = Wire(new MyBundle)
+ w1.foo := 5.U
+ w1.bar := 10.U
+ printf(cf"w1 = $w1")
+ }
+ generateAndCheck(new MyModule) {
+ case Seq(Printf("w1 = Bundle : Foo : %x Bar : %x", Seq("w1.foo", "w1.bar"))) =>
+ }
+ }
+
+ it should "support names of circuit elements using format specifier including submodule IO with cf format specifier" in {
+ // Submodule IO is a subtle issue because the Chisel element has a different
+ // parent module
+ class MySubModule extends Module {
+ val io = IO(new Bundle {
+ val fizz = UInt(32.W)
+ })
+ }
+ class MyBundle extends Bundle {
+ val foo = UInt(32.W)
+ }
+ class MyModule extends BasicTester {
+ override def desiredName: String = "MyModule"
+ val myWire = Wire(new MyBundle)
+ val myInst = Module(new MySubModule)
+ printf(cf"${myWire.foo}%n")
+ printf(cf"${myWire.foo}%N")
+ printf(cf"${myInst.io.fizz}%N")
+ }
+ generateAndCheck(new MyModule) {
+ case Seq(Printf("foo", Seq()), Printf("myWire.foo", Seq()), Printf("myInst.io.fizz", Seq())) =>
+ }
+ }
+
+ it should "correctly print strings after modifier" in {
+ class MyModule extends BasicTester {
+ val b1 = 10.U
+ printf(cf"This is here $b1%x!!!! And should print everything else")
+ }
+ generateAndCheck(new MyModule) {
+ case Seq(Printf("This is here %x!!!! And should print everything else", Seq("UInt<4>(\"ha\")"))) =>
+ }
+ }
+
+ it should "correctly print strings with a lot of literal %% and different format specifiers for Wires" in {
+ class MyModule extends BasicTester {
+ val b1 = 10.U
+ val b2 = 20.U
+ printf(cf"%% $b1%x%%$b2%b = ${b1 % b2}%d %%%% Tail String")
+ }
+
+ generateAndCheck(new MyModule) {
+ case Seq(Printf("%% %x%%%b = %d %%%% Tail String", Seq(lita, litb, _))) =>
+ assert(lita.contains("UInt<4>") && litb.contains("UInt<5>"))
+ }
+ }
+
+ it should "not allow unescaped % in the message" in {
+ class MyModule extends BasicTester {
+ printf(cf"This should error out for sure because of % - it should be %%")
+ }
+ a[java.util.UnknownFormatConversionException] should be thrownBy {
+ extractCause[java.util.UnknownFormatConversionException] {
+ ChiselStage.elaborate { new MyModule }
+ }
+ }
+ }
+
+ it should "allow Printables to be expanded and used" in {
+ class MyModule extends BasicTester {
+ val w1 = 20.U
+ val f1 = 30.2
+ val i1 = 14
+ val pable = cf"w1 = $w1%b f1 = $f1%2.2f"
+ printf(cf"Trying to expand printable $pable and mix with i1 = $i1%d")
+ }
+ generateAndCheck(new MyModule) {
+ case Seq(Printf("Trying to expand printable w1 = %b f1 = 30.20 and mix with i1 = 14", Seq(lit))) =>
+ assert(lit.contains("UInt<5>"))
+ }
+ }
+
+ it should "fail with a single % in the message" in {
+ class MyModule extends BasicTester {
+ printf(cf"%")
+ }
+ a[java.util.UnknownFormatConversionException] should be thrownBy {
+ extractCause[java.util.UnknownFormatConversionException] {
+ ChiselStage.elaborate { new MyModule }
+ }
+ }
+ }
+
+ it should "fail when passing directly to StirngContext.cf a string with literal \\ correctly escaped " in {
+ a[StringContext.InvalidEscapeException] should be thrownBy {
+ extractCause[StringContext.InvalidEscapeException] {
+ val s_seq = Seq("Test with literal \\ correctly escaped")
+ StringContext(s_seq: _*).cf(Seq(): _*)
+ }
+ }
+ }
+
+ it should "pass correctly escaped \\ when using Printable.pack" in {
+ class MyModule extends BasicTester {
+ printf(Printable.pack("\\ \\]"))
+ }
+ generateAndCheck(new MyModule) {
+ case Seq(Printf("\\\\ \\\\]", Seq())) =>
+ }
+ }
}
diff --git a/src/test/scala/chiselTests/SIntOps.scala b/src/test/scala/chiselTests/SIntOps.scala
index 55b4c915..ebbd2012 100644
--- a/src/test/scala/chiselTests/SIntOps.scala
+++ b/src/test/scala/chiselTests/SIntOps.scala
@@ -85,9 +85,9 @@ class SIntOpsTester(c: SIntOps) extends Tester(c) {
*/
class SIntLitExtractTester extends BasicTester {
- assert(-5.S(1) === true.B)
- assert(-5.S(2) === false.B)
- assert(-5.S(100) === true.B)
+ assert(-5.S.extract(1) === true.B)
+ assert(-5.S.extract(2) === false.B)
+ assert(-5.S.extract(100) === true.B)
assert(-5.S(3, 0) === "b1011".U)
assert(-5.S(9, 0) === "b1111111011".U)
assert(-5.S(4.W)(1) === true.B)
diff --git a/src/test/scala/chiselTests/StrongEnum.scala b/src/test/scala/chiselTests/StrongEnum.scala
index c43d832a..44ed77f9 100644
--- a/src/test/scala/chiselTests/StrongEnum.scala
+++ b/src/test/scala/chiselTests/StrongEnum.scala
@@ -4,8 +4,8 @@ package chiselTests
import chisel3._
import chisel3.experimental.ChiselEnum
+import chisel3.experimental.AffectsChiselPrefix
import chisel3.internal.firrtl.UnknownWidth
-import chisel3.internal.naming.chiselName
import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage}
import chisel3.util._
import chisel3.testers.BasicTester
@@ -575,11 +575,10 @@ class StrongEnumAnnotator extends Module {
val indexed2 = vec_of_bundles(cycle)
}
-@chiselName
class StrongEnumAnnotatorWithChiselName extends Module {
import EnumExample._
- object LocalEnum extends ChiselEnum {
+ object LocalEnum extends ChiselEnum with AffectsChiselPrefix {
val le0, le1 = Value
val le2 = Value
val le100 = Value(100.U)
diff --git a/src/test/scala/chiselTests/ToTargetSpec.scala b/src/test/scala/chiselTests/ToTargetSpec.scala
new file mode 100644
index 00000000..dc4ec448
--- /dev/null
+++ b/src/test/scala/chiselTests/ToTargetSpec.scala
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: Apache-2.0
+
+package chiselTests
+
+import chisel3._
+import chisel3.stage.ChiselStage
+import chisel3.util.Queue
+import chisel3.internal.ChiselException
+
+class ToTargetSpec extends ChiselFlatSpec with Utils {
+
+ var m: InstanceNameModule = _
+ ChiselStage.elaborate { m = new InstanceNameModule; m }
+
+ val mn = "InstanceNameModule"
+ val top = s"~$mn|$mn"
+
+ behavior.of(".toTarget")
+
+ val deprecationMsg = "Accessing the .instanceName or .toTarget of non-hardware Data is deprecated"
+
+ it should "work with module IO" in {
+ val io = m.io.toTarget.toString
+ assert(io == s"$top>io")
+ }
+
+ it should "not work for literals" in {
+ a[ChiselException] shouldBe thrownBy {
+ m.x.toTarget.toString
+ }
+ }
+
+ it should "work with non-hardware values (but be deprecated)" in {
+ val (ylog, y) = grabLog(m.y.toTarget.toString)
+ val (zlog, z) = grabLog(m.z.toTarget.toString)
+ assert(y == s"$top>y")
+ ylog should include(deprecationMsg)
+ assert(z == s"$top>z")
+ zlog should include(deprecationMsg)
+ }
+
+ it should "work with non-hardware bundle elements (but be deprecated)" in {
+ val (log, foo) = grabLog(m.z.foo.toTarget.toString)
+ log should include(deprecationMsg)
+ assert(foo == s"$top>z.foo")
+ }
+
+ it should "work with modules" in {
+ val q = m.q.toTarget.toString
+ assert(q == s"~$mn|Queue")
+ }
+}
diff --git a/src/test/scala/chiselTests/UIntOps.scala b/src/test/scala/chiselTests/UIntOps.scala
index 0010e9ac..2f55da9a 100644
--- a/src/test/scala/chiselTests/UIntOps.scala
+++ b/src/test/scala/chiselTests/UIntOps.scala
@@ -172,9 +172,9 @@ class MatchedRotateLeftAndRight(w: Int = 13) extends BasicTester {
}
class UIntLitExtractTester extends BasicTester {
- assert("b101010".U(2) === false.B)
- assert("b101010".U(3) === true.B)
- assert("b101010".U(100) === false.B)
+ assert("b101010".U.extract(2) === false.B)
+ assert("b101010".U.extract(3) === true.B)
+ assert("b101010".U.extract(100) === false.B)
assert("b101010".U(3, 0) === "b1010".U)
assert("b101010".U(9, 0) === "b0000101010".U)
diff --git a/src/test/scala/chiselTests/Vec.scala b/src/test/scala/chiselTests/Vec.scala
index 2eb6ae5f..02743187 100644
--- a/src/test/scala/chiselTests/Vec.scala
+++ b/src/test/scala/chiselTests/Vec.scala
@@ -517,4 +517,26 @@ class VecSpec extends ChiselPropSpec with Utils {
property("reduceTree should preserve input/output type") {
assertTesterPasses { new ReduceTreeTester() }
}
+
+ property("Vecs of empty Bundles and empty Records should work") {
+ class MyModule(gen: Record) extends Module {
+ val idx = IO(Input(UInt(2.W)))
+ val in = IO(Input(gen))
+ val out = IO(Output(gen))
+
+ val reg = RegInit(0.U.asTypeOf(Vec(4, gen)))
+ reg(idx) := in
+ out := reg(idx)
+ }
+ class EmptyBundle extends Bundle
+ class EmptyRecord extends Record {
+ val elements = collection.immutable.ListMap.empty
+ override def cloneType = (new EmptyRecord).asInstanceOf[this.type]
+ }
+ for (gen <- List(new EmptyBundle, new EmptyRecord)) {
+ val chirrtl = ChiselStage.emitChirrtl(new MyModule(gen))
+ chirrtl should include("input in : { }")
+ chirrtl should include("reg reg : { }[4]")
+ }
+ }
}
diff --git a/src/test/scala/chiselTests/VerificationSpec.scala b/src/test/scala/chiselTests/VerificationSpec.scala
index 95b0ffe6..32cee9e3 100644
--- a/src/test/scala/chiselTests/VerificationSpec.scala
+++ b/src/test/scala/chiselTests/VerificationSpec.scala
@@ -105,9 +105,9 @@ class VerificationSpec extends ChiselPropSpec with Matchers {
val firLines = scala.io.Source.fromFile(firFile).getLines.toList
// 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_7, UInt<1>(\"h1\"), \"\") : asst")
+ (exactly(1, firLines) should include).regex("^\\s*cover\\(.*\\) : cov")
+ (exactly(1, firLines) should include).regex("^\\s*assume\\(.*\\) : assm")
+ (exactly(1, firLines) should include).regex("^\\s*assert\\(.*\\) : asst")
}
property("annotation of verification constructs with suggested name should work") {
@@ -150,7 +150,7 @@ class VerificationSpec extends ChiselPropSpec with Matchers {
val firLines = scala.io.Source.fromFile(firFile).getLines.toList
// 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_4, UInt<1>(\"h1\"), \"\") : howdy")
+ (exactly(1, firLines) should include).regex("^\\s*assert\\(.*\\) : hello")
+ (exactly(1, firLines) should include).regex("^\\s*assume\\(.*\\) : howdy")
}
}
diff --git a/src/test/scala/chiselTests/experimental/DataMirrorSpec.scala b/src/test/scala/chiselTests/experimental/DataMirrorSpec.scala
new file mode 100644
index 00000000..731596ec
--- /dev/null
+++ b/src/test/scala/chiselTests/experimental/DataMirrorSpec.scala
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: Apache-2.0
+
+package chiselTests.experimental
+
+import chisel3._
+import chisel3.util.Valid
+import chisel3.stage.ChiselStage
+import chisel3.experimental.DataMirror
+import chiselTests.ChiselFlatSpec
+
+class DataMirrorSpec extends ChiselFlatSpec {
+ behavior.of("DataMirror")
+
+ def assertBinding(x: Data, io: Boolean, wire: Boolean, reg: Boolean) = {
+ DataMirror.isIO(x) should be(io)
+ DataMirror.isWire(x) should be(wire)
+ DataMirror.isReg(x) should be(reg)
+ }
+
+ def assertIO(x: Data) = assertBinding(x, true, false, false)
+
+ def assertWire(x: Data) = assertBinding(x, false, true, false)
+
+ def assertReg(x: Data) = assertBinding(x, false, false, true)
+
+ def assertNone(x: Data) = assertBinding(x, false, false, false)
+
+ it should "validate bindings" in {
+ class MyModule extends Module {
+ val typ = UInt(4.W)
+ val vectyp = Vec(8, UInt(4.W))
+ val io = IO(new Bundle {
+ val in = Input(UInt(4.W))
+ val vec = Input(vectyp)
+ val out = Output(UInt(4.W))
+ })
+ val vec = Wire(vectyp)
+ val regvec = Reg(vectyp)
+ val wire = Wire(UInt(4.W))
+ val reg = RegNext(wire)
+
+ assertIO(io)
+ assertIO(io.in)
+ assertIO(io.out)
+ assertIO(io.vec(1))
+ assertIO(io.vec)
+ assertWire(vec)
+ assertWire(vec(0))
+ assertWire(wire)
+ assertReg(reg)
+ assertReg(regvec)
+ assertReg(regvec(2))
+ assertNone(typ)
+ assertNone(vectyp)
+ }
+ ChiselStage.elaborate(new MyModule)
+ }
+}
diff --git a/src/test/scala/chiselTests/experimental/DataView.scala b/src/test/scala/chiselTests/experimental/DataView.scala
index e7caacfd..ac8357f0 100644
--- a/src/test/scala/chiselTests/experimental/DataView.scala
+++ b/src/test/scala/chiselTests/experimental/DataView.scala
@@ -479,6 +479,25 @@ class DataViewSpec extends ChiselFlatSpec {
(err.getMessage should fullyMatch).regex(expected)
}
+ it should "support invalidation" in {
+ class MyModule extends Module {
+ val a, b, c, d, e, f = IO(Output(UInt(8.W)))
+ val foo = (a, b).viewAs
+ val bar = (c, d).viewAs
+ val fizz = (e, f).viewAs
+ foo := DontCare
+ bar <> DontCare
+ fizz._1 := DontCare
+ fizz._2 <> DontCare
+ }
+
+ val chirrtl = ChiselStage.emitChirrtl(new MyModule)
+ val expected = ('a' to 'f').map(c => s"$c is invalid")
+ for (line <- expected) {
+ chirrtl should include(line)
+ }
+ }
+
behavior.of("PartialDataView")
it should "still error if the mapping is non-total in the view" in {
diff --git a/src/test/scala/chiselTests/experimental/hierarchy/SeparateElaborationSpec.scala b/src/test/scala/chiselTests/experimental/hierarchy/SeparateElaborationSpec.scala
new file mode 100644
index 00000000..25bbc474
--- /dev/null
+++ b/src/test/scala/chiselTests/experimental/hierarchy/SeparateElaborationSpec.scala
@@ -0,0 +1,495 @@
+// SPDX-License-Identifier: Apache-2.0
+
+package chiselTests.experimental.hierarchy
+
+import chiselTests.ChiselFunSpec
+import chisel3._
+import chisel3.stage.{ChiselCircuitAnnotation, ChiselGeneratorAnnotation, ChiselStage, DesignAnnotation}
+import chisel3.experimental.hierarchy.{Definition, Instance}
+import chisel3.experimental.hierarchy.ImportDefinitionAnnotation
+import firrtl.AnnotationSeq
+import firrtl.options.TargetDirAnnotation
+
+import scala.io.Source
+
+class SeparateElaborationSpec extends ChiselFunSpec with Utils {
+ import Examples._
+
+ /** Return a [[DesignAnnotation]] from a list of annotations. */
+ private def getDesignAnnotation[T <: RawModule](annos: AnnotationSeq): DesignAnnotation[T] = {
+ val designAnnos = annos.flatMap { a =>
+ a match {
+ case a: DesignAnnotation[T] => Some(a)
+ case _ => None
+ }
+ }
+ require(designAnnos.length == 1, s"Exactly one DesignAnnotation should exist, but found: $designAnnos.")
+ designAnnos.head
+ }
+
+ /** Elaborates [[AddOne]] and returns its [[Definition]]. */
+ private def getAddOneDefinition(testDir: String): Definition[AddOne] = {
+ val dutAnnos = (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new AddOne),
+ TargetDirAnnotation(testDir)
+ )
+ )
+
+ // Grab DUT definition to pass into testbench
+ getDesignAnnotation(dutAnnos).design.asInstanceOf[AddOne].toDefinition
+ }
+
+ /** Return [[Definition]]s of all modules in a circuit. */
+ private def allModulesToImportedDefs(annos: AnnotationSeq): Seq[ImportDefinitionAnnotation[_]] = {
+ annos.flatMap { a =>
+ a match {
+ case a: ChiselCircuitAnnotation =>
+ a.circuit.components.map { c => ImportDefinitionAnnotation(c.id.toDefinition) }
+ case _ => Seq.empty
+ }
+ }
+ }
+
+ describe("(0): Name conflicts") {
+ it("(0.a): should not occur between a Module and an Instance of a previously elaborated Definition.") {
+ val testDir = createTestDirectory(this.getClass.getSimpleName).toString
+
+ val dutDef = getAddOneDefinition(testDir)
+
+ class Testbench(defn: Definition[AddOne]) extends Module {
+ val mod = Module(new AddOne)
+ val inst = Instance(defn)
+
+ // Tie inputs to a value so ChiselStage does not complain
+ mod.in := 0.U
+ inst.in := 0.U
+ dontTouch(mod.out)
+ }
+
+ (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new Testbench(dutDef)),
+ TargetDirAnnotation(testDir),
+ ImportDefinitionAnnotation(dutDef)
+ )
+ )
+
+ val tb_rtl = Source.fromFile(s"$testDir/Testbench.v").getLines.mkString
+ tb_rtl should include("module AddOne_1(")
+ tb_rtl should include("AddOne_1 mod (")
+ (tb_rtl should not).include("module AddOne(")
+ tb_rtl should include("AddOne inst (")
+ }
+
+ it(
+ "(0.b): should not occur between an Instance of a Definition and an Instance of a previously elaborated Definition."
+ ) {
+ val testDir = createTestDirectory(this.getClass.getSimpleName).toString
+
+ val dutDef = getAddOneDefinition(testDir)
+
+ class Testbench(defn: Definition[AddOne]) extends Module {
+ val inst0 = Instance(Definition(new AddOne))
+ val inst1 = Instance(defn)
+
+ // Tie inputs to a value so ChiselStage does not complain
+ inst0.in := 0.U
+ inst1.in := 0.U
+ dontTouch(inst0.out)
+ }
+
+ (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new Testbench(dutDef)),
+ TargetDirAnnotation(testDir),
+ ImportDefinitionAnnotation(dutDef)
+ )
+ )
+
+ val tb_rtl = Source.fromFile(s"$testDir/Testbench.v").getLines.mkString
+ tb_rtl should include("module AddOne_1(")
+ tb_rtl should include("AddOne_1 inst0 (")
+ (tb_rtl should not).include("module AddOne(")
+ tb_rtl should include("AddOne inst1 (")
+ }
+ }
+
+ describe("(1): Repeat Module definitions") {
+ it("(1.a): should not occur when elaborating multiple Instances separately from its Definition.") {
+ val testDir = createTestDirectory(this.getClass.getSimpleName).toString
+
+ val dutDef = getAddOneDefinition(testDir)
+
+ class Testbench(defn: Definition[AddOne]) extends Module {
+ val inst0 = Instance(defn)
+ val inst1 = Instance(defn)
+
+ inst0.in := 0.U
+ inst1.in := 0.U
+ }
+
+ // If there is a repeat module definition, FIRRTL emission will fail
+ (new ChiselStage).emitFirrtl(
+ gen = new Testbench(dutDef),
+ args = Array("-td", testDir, "--full-stacktrace"),
+ annotations = Seq(ImportDefinitionAnnotation(dutDef))
+ )
+ }
+ }
+
+ describe("(2): Multiple imported Definitions of modules without submodules") {
+ it(
+ "(2.a): should work if a list of imported Definitions is passed between Stages."
+ ) {
+ val testDir = createTestDirectory(this.getClass.getSimpleName).toString
+
+ val dutAnnos0 = (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new AddOneParameterized(4)),
+ TargetDirAnnotation(s"$testDir/dutDef0")
+ )
+ )
+ val dutDef0 = getDesignAnnotation(dutAnnos0).design.asInstanceOf[AddOneParameterized].toDefinition
+
+ val dutAnnos1 = (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new AddOneParameterized(8)),
+ TargetDirAnnotation(s"$testDir/dutDef1"),
+ // pass in previously elaborated Definitions
+ ImportDefinitionAnnotation(dutDef0)
+ )
+ )
+ val dutDef1 = getDesignAnnotation(dutAnnos1).design.asInstanceOf[AddOneParameterized].toDefinition
+
+ class Testbench(defn0: Definition[AddOneParameterized], defn1: Definition[AddOneParameterized]) extends Module {
+ val inst0 = Instance(defn0)
+ val inst1 = Instance(defn1)
+
+ // Tie inputs to a value so ChiselStage does not complain
+ inst0.in := 0.U
+ inst1.in := 0.U
+ }
+
+ (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new Testbench(dutDef0, dutDef1)),
+ TargetDirAnnotation(testDir),
+ ImportDefinitionAnnotation(dutDef0),
+ ImportDefinitionAnnotation(dutDef1)
+ )
+ )
+
+ val dutDef0_rtl = Source.fromFile(s"$testDir/dutDef0/AddOneParameterized.v").getLines.mkString
+ dutDef0_rtl should include("module AddOneParameterized(")
+ val dutDef1_rtl = Source.fromFile(s"$testDir/dutDef1/AddOneParameterized_1.v").getLines.mkString
+ dutDef1_rtl should include("module AddOneParameterized_1(")
+
+ val tb_rtl = Source.fromFile(s"$testDir/Testbench.v").getLines.mkString
+ tb_rtl should include("AddOneParameterized inst0 (")
+ tb_rtl should include("AddOneParameterized_1 inst1 (")
+ (tb_rtl should not).include("module AddOneParameterized(")
+ (tb_rtl should not).include("module AddOneParameterized_1(")
+ }
+
+ it(
+ "(2.b): should throw an exception if information is not passed between Stages."
+ ) {
+ val testDir = createTestDirectory(this.getClass.getSimpleName).toString
+
+ val dutAnnos0 = (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new AddOneParameterized(4)),
+ TargetDirAnnotation(s"$testDir/dutDef0")
+ )
+ )
+ val dutDef0 = getDesignAnnotation(dutAnnos0).design.asInstanceOf[AddOneParameterized].toDefinition
+
+ val dutAnnos1 = (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new AddOneParameterized(8)),
+ TargetDirAnnotation(s"$testDir/dutDef1")
+ )
+ )
+ val dutDef1 = getDesignAnnotation(dutAnnos1).design.asInstanceOf[AddOneParameterized].toDefinition
+
+ class Testbench(defn0: Definition[AddOneParameterized], defn1: Definition[AddOneParameterized]) extends Module {
+ val inst0 = Instance(defn0)
+ val inst1 = Instance(defn1)
+
+ // Tie inputs to a value so ChiselStage does not complain
+ inst0.in := 0.U
+ inst1.in := 0.U
+ }
+
+ // Because these elaborations have no knowledge of each other, they create
+ // modules of the same name
+ val dutDef0_rtl = Source.fromFile(s"$testDir/dutDef0/AddOneParameterized.v").getLines.mkString
+ dutDef0_rtl should include("module AddOneParameterized(")
+ val dutDef1_rtl = Source.fromFile(s"$testDir/dutDef1/AddOneParameterized.v").getLines.mkString
+ dutDef1_rtl should include("module AddOneParameterized(")
+
+ val errMsg = intercept[ChiselException] {
+ (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new Testbench(dutDef0, dutDef1)),
+ TargetDirAnnotation(testDir),
+ ImportDefinitionAnnotation(dutDef0),
+ ImportDefinitionAnnotation(dutDef1)
+ )
+ )
+ }
+ errMsg.getMessage should include(
+ "Expected distinct imported Definition names but found duplicates for: AddOneParameterized"
+ )
+ }
+ }
+
+ describe("(3): Multiple imported Definitions of modules with submodules") {
+ it(
+ "(3.a): should work if a list of imported Definitions for all modules is passed between Stages."
+ ) {
+ val testDir = createTestDirectory(this.getClass.getSimpleName).toString
+
+ val dutAnnos0 = (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new AddTwoMixedModules),
+ TargetDirAnnotation(s"$testDir/dutDef0")
+ )
+ )
+ val dutDef0 = getDesignAnnotation(dutAnnos0).design.asInstanceOf[AddTwoMixedModules].toDefinition
+ val importDefinitionAnnos0 = allModulesToImportedDefs(dutAnnos0)
+
+ val dutAnnos1 = (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new AddTwoMixedModules),
+ TargetDirAnnotation(s"$testDir/dutDef1")
+ ) ++ importDefinitionAnnos0
+ )
+ val dutDef1 = getDesignAnnotation(dutAnnos1).design.asInstanceOf[AddTwoMixedModules].toDefinition
+ val importDefinitionAnnos1 = allModulesToImportedDefs(dutAnnos1)
+
+ class Testbench(defn0: Definition[AddTwoMixedModules], defn1: Definition[AddTwoMixedModules]) extends Module {
+ val inst0 = Instance(defn0)
+ val inst1 = Instance(defn1)
+
+ // Tie inputs to a value so ChiselStage does not complain
+ inst0.in := 0.U
+ inst1.in := 0.U
+ }
+
+ val dutDef0_rtl = Source.fromFile(s"$testDir/dutDef0/AddTwoMixedModules.v").getLines.mkString
+ dutDef0_rtl should include("module AddOne(")
+ dutDef0_rtl should include("module AddTwoMixedModules(")
+ val dutDef1_rtl = Source.fromFile(s"$testDir/dutDef1/AddTwoMixedModules_1.v").getLines.mkString
+ dutDef1_rtl should include("module AddOne_2(")
+ dutDef1_rtl should include("module AddTwoMixedModules_1(")
+
+ (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new Testbench(dutDef0, dutDef1)),
+ TargetDirAnnotation(testDir)
+ ) ++ importDefinitionAnnos0 ++ importDefinitionAnnos1
+ )
+
+ val tb_rtl = Source.fromFile(s"$testDir/Testbench.v").getLines.mkString
+ tb_rtl should include("AddTwoMixedModules inst0 (")
+ tb_rtl should include("AddTwoMixedModules_1 inst1 (")
+ (tb_rtl should not).include("module AddTwoMixedModules(")
+ (tb_rtl should not).include("module AddTwoMixedModules_1(")
+ }
+ }
+
+ it(
+ "(3.b): should throw an exception if submodules are not passed between Definition elaborations."
+ ) {
+ val testDir = createTestDirectory(this.getClass.getSimpleName).toString
+
+ val dutAnnos0 = (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new AddTwoMixedModules),
+ TargetDirAnnotation(s"$testDir/dutDef0")
+ )
+ )
+ val dutDef0 = getDesignAnnotation(dutAnnos0).design.asInstanceOf[AddTwoMixedModules].toDefinition
+ val importDefinitionAnnos0 = allModulesToImportedDefs(dutAnnos0)
+
+ val dutAnnos1 = (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new AddTwoMixedModules),
+ ImportDefinitionAnnotation(dutDef0),
+ TargetDirAnnotation(s"$testDir/dutDef1")
+ )
+ )
+ val dutDef1 = getDesignAnnotation(dutAnnos1).design.asInstanceOf[AddTwoMixedModules].toDefinition
+ val importDefinitionAnnos1 = allModulesToImportedDefs(dutAnnos1)
+
+ class Testbench(defn0: Definition[AddTwoMixedModules], defn1: Definition[AddTwoMixedModules]) extends Module {
+ val inst0 = Instance(defn0)
+ val inst1 = Instance(defn1)
+
+ // Tie inputs to a value so ChiselStage does not complain
+ inst0.in := 0.U
+ inst1.in := 0.U
+ }
+
+ val dutDef0_rtl = Source.fromFile(s"$testDir/dutDef0/AddTwoMixedModules.v").getLines.mkString
+ dutDef0_rtl should include("module AddOne(")
+ dutDef0_rtl should include("module AddTwoMixedModules(")
+ val dutDef1_rtl = Source.fromFile(s"$testDir/dutDef1/AddTwoMixedModules_1.v").getLines.mkString
+ dutDef1_rtl should include("module AddOne(")
+ dutDef1_rtl should include("module AddTwoMixedModules_1(")
+
+ val errMsg = intercept[ChiselException] {
+ (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new Testbench(dutDef0, dutDef1)),
+ TargetDirAnnotation(testDir)
+ ) ++ importDefinitionAnnos0 ++ importDefinitionAnnos1
+ )
+ }
+ errMsg.getMessage should include(
+ "Expected distinct imported Definition names but found duplicates for: AddOne"
+ )
+ }
+
+ describe("(4): With ExtMod Names") {
+ it("(4.a): should pick correct ExtMod names when passed") {
+ val testDir = createTestDirectory(this.getClass.getSimpleName).toString
+
+ val dutDef = getAddOneDefinition(testDir)
+
+ class Testbench(defn: Definition[AddOne]) extends Module {
+ val mod = Module(new AddOne)
+ val inst = Instance(defn)
+
+ // Tie inputs to a value so ChiselStage does not complain
+ mod.in := 0.U
+ inst.in := 0.U
+ dontTouch(mod.out)
+ }
+
+ (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new Testbench(dutDef)),
+ TargetDirAnnotation(testDir),
+ ImportDefinitionAnnotation(dutDef, Some("CustomPrefix_AddOne_CustomSuffix"))
+ )
+ )
+
+ val tb_rtl = Source.fromFile(s"$testDir/Testbench.v").getLines.mkString
+
+ tb_rtl should include("module AddOne_1(")
+ tb_rtl should include("AddOne_1 mod (")
+ (tb_rtl should not).include("module AddOne(")
+ tb_rtl should include("CustomPrefix_AddOne_CustomSuffix inst (")
+ }
+ }
+
+ it(
+ "(4.b): should work if a list of imported Definitions is passed between Stages with ExtModName."
+ ) {
+ val testDir = createTestDirectory(this.getClass.getSimpleName).toString
+
+ val dutAnnos0 = (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new AddOneParameterized(4)),
+ TargetDirAnnotation(s"$testDir/dutDef0")
+ )
+ )
+ val dutDef0 = getDesignAnnotation(dutAnnos0).design.asInstanceOf[AddOneParameterized].toDefinition
+
+ val dutAnnos1 = (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new AddOneParameterized(8)),
+ TargetDirAnnotation(s"$testDir/dutDef1"),
+ // pass in previously elaborated Definitions
+ ImportDefinitionAnnotation(dutDef0)
+ )
+ )
+ val dutDef1 = getDesignAnnotation(dutAnnos1).design.asInstanceOf[AddOneParameterized].toDefinition
+
+ class Testbench(defn0: Definition[AddOneParameterized], defn1: Definition[AddOneParameterized]) extends Module {
+ val inst0 = Instance(defn0)
+ val inst1 = Instance(defn1)
+
+ // Tie inputs to a value so ChiselStage does not complain
+ inst0.in := 0.U
+ inst1.in := 0.U
+ }
+
+ (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new Testbench(dutDef0, dutDef1)),
+ TargetDirAnnotation(testDir),
+ ImportDefinitionAnnotation(dutDef0, Some("Inst1_Prefix_AddOnePramaterized_Inst1_Suffix")),
+ ImportDefinitionAnnotation(dutDef1, Some("Inst2_Prefix_AddOnePrameterized_1_Inst2_Suffix"))
+ )
+ )
+
+ val dutDef0_rtl = Source.fromFile(s"$testDir/dutDef0/AddOneParameterized.v").getLines.mkString
+ dutDef0_rtl should include("module AddOneParameterized(")
+ val dutDef1_rtl = Source.fromFile(s"$testDir/dutDef1/AddOneParameterized_1.v").getLines.mkString
+ dutDef1_rtl should include("module AddOneParameterized_1(")
+
+ val tb_rtl = Source.fromFile(s"$testDir/Testbench.v").getLines.mkString
+ tb_rtl should include("Inst1_Prefix_AddOnePramaterized_Inst1_Suffix inst0 (")
+ tb_rtl should include("Inst2_Prefix_AddOnePrameterized_1_Inst2_Suffix inst1 (")
+ (tb_rtl should not).include("module AddOneParameterized(")
+ (tb_rtl should not).include("module AddOneParameterized_1(")
+ }
+
+ it(
+ "(4.c): should throw an exception if a list of imported Definitions is passed between Stages with same ExtModName."
+ ) {
+ val testDir = createTestDirectory(this.getClass.getSimpleName).toString
+
+ val dutAnnos0 = (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new AddOneParameterized(4)),
+ TargetDirAnnotation(s"$testDir/dutDef0")
+ )
+ )
+ val importDefinitionAnnos0 = allModulesToImportedDefs(dutAnnos0)
+ val dutDef0 = getDesignAnnotation(dutAnnos0).design.asInstanceOf[AddOneParameterized].toDefinition
+
+ val dutAnnos1 = (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new AddOneParameterized(8)),
+ TargetDirAnnotation(s"$testDir/dutDef1"),
+ // pass in previously elaborated Definitions
+ ImportDefinitionAnnotation(dutDef0)
+ )
+ )
+ val importDefinitionAnnos1 = allModulesToImportedDefs(dutAnnos1)
+ val dutDef1 = getDesignAnnotation(dutAnnos1).design.asInstanceOf[AddOneParameterized].toDefinition
+
+ class Testbench(defn0: Definition[AddOneParameterized], defn1: Definition[AddOneParameterized]) extends Module {
+ val inst0 = Instance(defn0)
+ val inst1 = Instance(defn1)
+
+ // Tie inputs to a value so ChiselStage does not complain
+ inst0.in := 0.U
+ inst1.in := 0.U
+ }
+
+ val dutDef0_rtl = Source.fromFile(s"$testDir/dutDef0/AddOneParameterized.v").getLines.mkString
+ dutDef0_rtl should include("module AddOneParameterized(")
+ val dutDef1_rtl = Source.fromFile(s"$testDir/dutDef1/AddOneParameterized_1.v").getLines.mkString
+ dutDef1_rtl should include("module AddOneParameterized_1(")
+
+ val errMsg = intercept[ChiselException] {
+ (new ChiselStage).run(
+ Seq(
+ ChiselGeneratorAnnotation(() => new Testbench(dutDef0, dutDef1)),
+ TargetDirAnnotation(testDir),
+ ImportDefinitionAnnotation(dutDef0, Some("Inst1_Prefix_AddOnePrameterized_Inst1_Suffix")),
+ ImportDefinitionAnnotation(dutDef1, Some("Inst1_Prefix_AddOnePrameterized_Inst1_Suffix"))
+ )
+ )
+ }
+ errMsg.getMessage should include(
+ "Expected distinct overrideDef names but found duplicates for: Inst1_Prefix_AddOnePrameterized_Inst1_Suffix"
+ )
+ }
+}
diff --git a/src/test/scala/chiselTests/naming/NamePluginSpec.scala b/src/test/scala/chiselTests/naming/NamePluginSpec.scala
index 18359fd2..a787bb80 100644
--- a/src/test/scala/chiselTests/naming/NamePluginSpec.scala
+++ b/src/test/scala/chiselTests/naming/NamePluginSpec.scala
@@ -3,6 +3,7 @@
package chiselTests.naming
import chisel3._
+import chisel3.stage.ChiselStage
import chisel3.aop.Select
import chisel3.experimental.{prefix, treedump}
import chiselTests.{ChiselFlatSpec, Utils}
@@ -69,6 +70,24 @@ class NamePluginSpec extends ChiselFlatSpec with Utils {
}
}
+ "Scala plugin" should "name verification ops" in {
+ class Test extends Module {
+ val foo, bar = IO(Input(UInt(8.W)))
+
+ {
+ val x1 = chisel3.assert(1.U === 1.U)
+ val x2 = cover(foo =/= bar)
+ val x3 = chisel3.assume(foo =/= 123.U)
+ val x4 = printf("foo = %d\n", foo)
+ }
+ }
+ val chirrtl = ChiselStage.emitChirrtl(new Test)
+ (chirrtl should include).regex("assert.*: x1")
+ (chirrtl should include).regex("cover.*: x2")
+ (chirrtl should include).regex("assume.*: x3")
+ (chirrtl should include).regex("printf.*: x4")
+ }
+
"Naming on option" should "work" in {
class Test extends Module {
@@ -321,4 +340,23 @@ class NamePluginSpec extends ChiselFlatSpec with Utils {
Select.wires(top).map(_.instanceName) should be(List("a_b_c", "a_b", "a"))
}
}
+
+ behavior.of("Unnamed values (aka \"Temporaries\")")
+
+ they should "be declared by starting the name with '_'" in {
+ class Test extends Module {
+ {
+ val a = {
+ val b = {
+ val _c = Wire(UInt(3.W))
+ 4.U // literal so there is no name
+ }
+ b
+ }
+ }
+ }
+ aspectTest(() => new Test) { top: Test =>
+ Select.wires(top).map(_.instanceName) should be(List("_a_b_c"))
+ }
+ }
}
diff --git a/src/test/scala/chiselTests/naming/PrefixSpec.scala b/src/test/scala/chiselTests/naming/PrefixSpec.scala
index f9a78f0e..6d52407e 100644
--- a/src/test/scala/chiselTests/naming/PrefixSpec.scala
+++ b/src/test/scala/chiselTests/naming/PrefixSpec.scala
@@ -3,6 +3,7 @@
package chiselTests.naming
import chisel3._
+import chisel3.stage.ChiselStage
import chisel3.aop.Select
import chisel3.experimental.{dump, noPrefix, prefix, treedump}
import chiselTests.{ChiselPropSpec, Utils}
@@ -232,18 +233,46 @@ class PrefixSpec extends ChiselPropSpec with Utils {
}
}
- property("Prefixing should be the prefix during the last call to autoName/suggestName") {
+ property("Prefixing should NOT be influenced by suggestName") {
class Test extends Module {
{
val wire = {
- val x = Wire(UInt(3.W)).suggestName("mywire")
- x
+ val x = Wire(UInt(3.W)) // wire_x
+ Wire(UInt(3.W)).suggestName("foo")
+ }
+ }
+ }
+ aspectTest(() => new Test) { top: Test =>
+ Select.wires(top).map(_.instanceName) should be(List("wire_x", "foo"))
+ }
+ }
+
+ property("Prefixing should be influenced by the \"current name\" of the signal") {
+ class Test extends Module {
+ {
+ val wire = {
+ val y = Wire(UInt(3.W)).suggestName("foo")
+ val x = Wire(UInt(3.W)) // wire_x
+ y
+ }
+
+ val wire2 = Wire(UInt(3.W))
+ wire2 := {
+ val x = Wire(UInt(3.W)) // wire2_x
+ x + 1.U
+ }
+ wire2.suggestName("bar")
+
+ val wire3 = Wire(UInt(3.W))
+ wire3.suggestName("fizz")
+ wire3 := {
+ val x = Wire(UInt(3.W)) // fizz_x
+ x + 1.U
}
}
}
aspectTest(() => new Test) { top: Test =>
- Select.wires(top).map(_.instanceName) should be(List("mywire"))
- Select.wires(top).map(_.instanceName) shouldNot be(List("wire_mywire"))
+ Select.wires(top).map(_.instanceName) should be(List("foo", "wire_x", "bar", "wire2_x", "fizz", "fizz_x"))
}
}
@@ -391,6 +420,81 @@ class PrefixSpec extends ChiselPropSpec with Utils {
aspectTest(() => new Test) { top: Test =>
Select.wires(top).map(_.instanceName) should be(List("x", "x_w_w", "x_w_w_w", "x_w_w_w_w"))
}
+ }
+
+ property("Prefixing should work for verification ops") {
+ class Test extends Module {
+ val foo, bar = IO(Input(UInt(8.W)))
+
+ {
+ val x5 = {
+ val x1 = chisel3.assert(1.U === 1.U)
+ val x2 = cover(foo =/= bar)
+ val x3 = chisel3.assume(foo =/= 123.U)
+ val x4 = printf("foo = %d\n", foo)
+ x1
+ }
+ }
+ }
+ val chirrtl = ChiselStage.emitChirrtl(new Test)
+ (chirrtl should include).regex("assert.*: x5")
+ (chirrtl should include).regex("cover.*: x5_x2")
+ (chirrtl should include).regex("assume.*: x5_x3")
+ (chirrtl should include).regex("printf.*: x5_x4")
+ }
+ property("Leading '_' in val names should be ignored in prefixes") {
+ class Test extends Module {
+ {
+ val a = {
+ val _b = {
+ val c = Wire(UInt(3.W))
+ 4.U // literal because there is no name
+ }
+ _b
+ }
+ }
+ }
+ aspectTest(() => new Test) { top: Test =>
+ Select.wires(top).map(_.instanceName) should be(List("a_b_c"))
+ }
+ }
+
+ // This checks that we don't just blanket ignore leading _ in prefixes
+ property("User-specified prefixes with '_' should be respected") {
+ class Test extends Module {
+ {
+ val a = {
+ val _b = prefix("_b") {
+ val c = Wire(UInt(3.W))
+ }
+ 4.U
+ }
+ }
+ }
+ aspectTest(() => new Test) { top: Test =>
+ Select.wires(top).map(_.instanceName) should be(List("a__b_c"))
+ }
+ }
+
+ property("Leading '_' in signal names should be ignored in prefixes from connections") {
+ class Test extends Module {
+ {
+ val a = {
+ val b = {
+ val _c = IO(Output(UInt(3.W))) // port so not selected as wire
+ _c := {
+ val d = Wire(UInt(3.W))
+ d
+ }
+ 4.U // literal so there is no name
+ }
+ b
+ }
+ }
+ }
+ aspectTest(() => new Test) { top: Test =>
+ Select.wires(top).map(_.instanceName) should be(List("a_b_c_d"))
+ }
}
}
diff --git a/src/test/scala/chiselTests/naming/ReflectiveNamingSpec.scala b/src/test/scala/chiselTests/naming/ReflectiveNamingSpec.scala
new file mode 100644
index 00000000..baa991dd
--- /dev/null
+++ b/src/test/scala/chiselTests/naming/ReflectiveNamingSpec.scala
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: Apache-2.0
+
+package chiselTests.naming
+
+import chisel3._
+import chiselTests.{ChiselFlatSpec, Utils}
+
+class ReflectiveNamingSpec extends ChiselFlatSpec with Utils {
+
+ behavior.of("Reflective naming")
+
+ private def emitChirrtl(gen: => RawModule): String = {
+ // Annoyingly need to emit files to use CLI
+ val targetDir = createTestDirectory(this.getClass.getSimpleName).toString
+ val args = Array("--warn:reflective-naming", "-td", targetDir)
+ (new chisel3.stage.ChiselStage).emitChirrtl(gen, args)
+ }
+
+ it should "NOT warn when no names are changed" in {
+ class Example extends Module {
+ val foo, bar = IO(Input(UInt(8.W)))
+ val out = IO(Output(UInt(8.W)))
+
+ val sum = foo +& bar
+ out := sum
+ }
+ val (log, chirrtl) = grabLog(emitChirrtl(new Example))
+ log should equal("")
+ chirrtl should include("node sum = add(foo, bar)")
+ }
+
+ it should "warn when changing the name of a node" in {
+ class Example extends Module {
+ val foo, bar = IO(Input(UInt(8.W)))
+ val out = IO(Output(UInt(8.W)))
+
+ val sum = foo +& bar
+ val fuzz = sum
+ out := sum
+ }
+ val (log, chirrtl) = grabLog(emitChirrtl(new Example))
+ log should include("'sum' is renamed by reflection to 'fuzz'")
+ chirrtl should include("node fuzz = add(foo, bar)")
+ }
+
+ // This also checks correct prefix reversing
+ it should "warn when changing the name of a node with a prefix in the name" in {
+ class Example extends Module {
+ val foo, bar = IO(Input(UInt(8.W)))
+ val out = IO(Output(UInt(8.W)))
+
+ // This is sketch, don't do this
+ var fuzz = 0.U
+ out := {
+ val sum = {
+ val node = foo +& bar
+ fuzz = node
+ node +% 0.U
+ }
+ sum
+ }
+ }
+ val (log, chirrtl) = grabLog(emitChirrtl(new Example))
+ log should include("'out_sum_node' is renamed by reflection to 'fuzz'")
+ chirrtl should include("node fuzz = add(foo, bar)")
+ }
+
+ it should "warn when changing the name of a Module instance" in {
+ import chisel3.util._
+ class Example extends Module {
+ val enq = IO(Flipped(Decoupled(UInt(8.W))))
+ val deq = IO(Decoupled(UInt(8.W)))
+
+ val q = Module(new Queue(UInt(8.W), 4))
+ q.io.enq <> enq
+ deq <> q.io.deq
+
+ val fuzz = q
+ }
+ val (log, chirrtl) = grabLog(emitChirrtl(new Example))
+ log should include("'q' is renamed by reflection to 'fuzz'")
+ chirrtl should include("inst fuzz of Queue")
+ }
+
+ it should "warn when changing the name of an Instance" in {
+ import chisel3.experimental.hierarchy.{Definition, Instance}
+ import chiselTests.experimental.hierarchy.Examples.AddOne
+ class Example extends Module {
+ val defn = Definition(new AddOne)
+ val inst = Instance(defn)
+ val fuzz = inst
+ }
+ val (log, chirrtl) = grabLog(emitChirrtl(new Example))
+ log should include("'inst' is renamed by reflection to 'fuzz'")
+ chirrtl should include("inst fuzz of AddOne")
+ }
+
+ it should "warn when changing the name of a Mem" in {
+ class Example extends Module {
+ val mem = SyncReadMem(8, UInt(8.W))
+
+ val fuzz = mem
+ }
+ val (log, chirrtl) = grabLog(emitChirrtl(new Example))
+ log should include("'mem' is renamed by reflection to 'fuzz'")
+ chirrtl should include("smem fuzz")
+ }
+
+ it should "NOT warn when changing the name of a verification statement" in {
+ class Example extends Module {
+ val in = IO(Input(UInt(8.W)))
+ val z = chisel3.assert(in =/= 123.U)
+ val fuzz = z
+ }
+ val (log, chirrtl) = grabLog(emitChirrtl(new Example))
+ log should equal("")
+ // But the name is actually changed
+ (chirrtl should include).regex("assert.*: fuzz")
+ }
+
+ it should "NOT warn when \"naming\" a literal" in {
+ class Example extends Module {
+ val out = IO(Output(UInt(8.W)))
+
+ val sum = 0.U
+ val fuzz = sum
+ out := sum
+ }
+ val (log, chirrtl) = grabLog(emitChirrtl(new Example))
+ log should equal("")
+ chirrtl should include("out <= UInt")
+ }
+
+ it should "NOT warn when \"naming\" a field of an Aggregate" in {
+ class Example extends Module {
+ val io = IO(new Bundle {
+ val in = Input(UInt(8.W))
+ val out = Output(UInt(8.W))
+ })
+ val in = io.in
+ val out = io.out
+ out := in
+ }
+ val (log, chirrtl) = grabLog(emitChirrtl(new Example))
+ log should equal("")
+ chirrtl should include("io.out <= io.in")
+ }
+
+ it should "NOT warn when \"naming\" unbound Data" in {
+ class Example extends Module {
+ val in = IO(Input(UInt(8.W)))
+ val out = IO(Output(UInt(8.W)))
+ val z = UInt(8.W)
+ val a = z
+ out := in
+ }
+ val (log, chirrtl) = grabLog(emitChirrtl(new Example))
+ log should equal("")
+ chirrtl should include("out <= in")
+ }
+}
diff --git a/src/test/scala/chiselTests/util/experimental/TruthTableSpec.scala b/src/test/scala/chiselTests/util/experimental/TruthTableSpec.scala
index fa2c6f08..9b2dd600 100644
--- a/src/test/scala/chiselTests/util/experimental/TruthTableSpec.scala
+++ b/src/test/scala/chiselTests/util/experimental/TruthTableSpec.scala
@@ -104,4 +104,21 @@ class TruthTableSpec extends AnyFlatSpec {
assert(t.toString contains "111->?")
assert(t.toString contains " 0")
}
+
+ "Using TruthTable.fromEspressoOutput" should "merge rows on conflict" in {
+ val mapping = List(
+ (BitPat("b110"), BitPat("b001")),
+ (BitPat("b111"), BitPat("b001")),
+ (BitPat("b111"), BitPat("b010")),
+ (BitPat("b111"), BitPat("b100"))
+ )
+
+ assert(
+ TruthTable.fromEspressoOutput(mapping, BitPat("b?")) ==
+ TruthTable.fromString("""110->001
+ |111->111
+ |?
+ |""".stripMargin)
+ )
+ }
}