From 8fa46071c382b6fdecba86a9bab729526fa4fbe2 Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Thu, 4 Feb 2021 10:07:56 -0800 Subject: Minor docs improvements (#1774) * Fix some botched formatting (replace ```mdoc scala with ```scala mdoc) * Replace some unnecessary uses of triple backticks with single backticks * Move appendix docs from wiki-deprecated/ to appendix/ * This will require an update on the website as well * Update Bundle literal docs--- docs/src/appendix/chisel3-vs-chisel2.md | 203 +++++++++++++++++++++ docs/src/appendix/experimental-features.md | 138 ++++++++++++++ docs/src/appendix/upgrading-from-scala-2-11.md | 88 +++++++++ docs/src/explanations/blackboxes.md | 50 ++--- docs/src/explanations/bundles-and-vecs.md | 24 +-- docs/src/wiki-deprecated/chisel3-vs-chisel2.md | 203 --------------------- docs/src/wiki-deprecated/experimental-features.md | 119 ------------ .../wiki-deprecated/upgrading-from-scala-2-11.md | 88 --------- 8 files changed, 464 insertions(+), 449 deletions(-) create mode 100644 docs/src/appendix/chisel3-vs-chisel2.md create mode 100644 docs/src/appendix/experimental-features.md create mode 100644 docs/src/appendix/upgrading-from-scala-2-11.md delete mode 100644 docs/src/wiki-deprecated/chisel3-vs-chisel2.md delete mode 100644 docs/src/wiki-deprecated/experimental-features.md delete mode 100644 docs/src/wiki-deprecated/upgrading-from-scala-2-11.md (limited to 'docs') diff --git a/docs/src/appendix/chisel3-vs-chisel2.md b/docs/src/appendix/chisel3-vs-chisel2.md new file mode 100644 index 00000000..bfd20348 --- /dev/null +++ b/docs/src/appendix/chisel3-vs-chisel2.md @@ -0,0 +1,203 @@ +--- +layout: docs +title: "Chisel3 vs. Chisel2" +section: "chisel3" +--- + +# Chisel3 vs Chisel2 + +## Chisel2 Migration +For those moving from Chisel2, there were some backwards incompatible changes +and your RTL needs to be modified to work with Chisel3. The required +modifications are: + + - Wire declaration style: + ```scala + val wire = UInt(width = 15) + ``` + becomes (in Chisel3): + ```scala + val wire = Wire(UInt(15.W)) + ``` + + - I/O declaration style: + ```scala + val done = Bool(OUTPUT) + ``` + becomes (in Chisel3): + ```scala + val wire = Output(Bool()) + ``` + + - Sequential memories: + ```scala + val addr = Reg(UInt()) + val mem = Mem(UInt(8.W), 1024, seqRead = true) + val dout = when(enable) { mem(addr) } + ``` + becomes (in Chisel3): + ```scala + val addr = UInt() + val mem = SyncReadMem(1024, UInt(8.W)) + val dout = mem.read(addr, enable) + ``` + + Notice the address register is now internal to the SyncReadMem(), but the data + will still return on the subsequent cycle. + + - Generating Verilog with + ```scala + object Hello { + def main(args: Array[String]): Unit = { + chiselMain(Array("--backend", "v"), () => Module(new Hello())) + } + } + ``` + becomes (in Chisel3): + ```scala + object Hello { + def main(args: Array[String]): Unit = { + chisel3.Driver.execute(Array[String](), () => new Hello()) + } + } + ``` + + - Package changes: + - Chisel.log2Ceil -> chisel3.util.log2Ceil + - BitPat + - Decoupled is also in chisel3.util + +Please refer to the [Chisel3 compatibility section](https://github.com/ucb-bar/chisel#chisel3) +for instructions on preparing your Chisel2 designs for Chisel3. + +## Deprecated Usage +* `Vec(Reg)` should be replaced with `Reg(Vec)`, +* type-only vals (no associated data) must be wrapped in a `Wire()` if they will be the destination of a wiring operation (":=" or " < >"), +* masked bit patterns ('b??') should be created using BitPat(), not UInt() or Bits(), +* the `clone` method required for parameterized Bundles has been renamed `cloneType`, +* the con and alt inputs to a Mux must be type-compatible - both signed or both unsigned, +* bulk-connection to a node that has been procedurally assigned-to is illegal, +* `!=` is deprecated, use `=/=` instead, +* use `SyncReadMem(...)` instead of `Mem(..., seqRead)`, +* use `SyncReadMem(n:Int, out: => T)` instead of `SyncReadMem(out: => T, n:Int)`, +* use `SyncReadMem(...)` instead of `SeqMem(...)`, +* use `Mem(n:Int, t:T)` instead of `Mem(out:T, n:Int)`, +* use `Vec(n:Int, gen: => T)` instead of `Vec(gen: => T, n:Int)`, +* module io's must be wrapped in `IO()`. +* The methods `asInput`, `asOutput`, and `flip` should be replaced by the `Input()`, `Output()`, and `Flipped()` object apply methods. + +## Unsupported constructs +* `Mem(..., orderedWrites)` is no longer supported, +* masked writes are only supported for `Mem[Vec[_]]`, +* Chisel3 Vecs must all have the same type, unlike with Chisel2. Use `MixedVec` (see [Bundles and Vecs](../explanations/bundles-and-vecs)) for Vecs where the elements are of different types. +* connections between `UInt` and `SInt` are illegal. +* the `Node` class and object no longer exist (the class should have been private in Chisel2) +* `printf()` is defined in the Chisel object and produces simulation printf()'s. +To use the Scala `Predef.printf()`, you need to qualify it with `Predef`. +* in Chisel2, bulk-connects `<>` with unconnected source components do not update connections from the unconnected components. +** In Chisel3, bulk-connects strictly adhere to last connection semantics and unconnected OUTPUTs will be connected to INPUTs resulting in the assignment of random values to those inputs. +* In Chisel3, adding hardware inside `BlackBox` for simulation is no longer supported. (#289) +* `ChiselError` is gone + * Change `ChiselError.error("error msg")` to `throw new Error("error msg")` + * Change `ChiselError.info("info msg")` to `println("info msg")` +* In Chisel3, subword assignments are not supported. [Alternative constructions exist](https://github.com/freechipsproject/chisel3/wiki/Cookbook#how-do-i-do-subword-assignment-assign-to-some-bits-in-a-uint) in Chisel3. + +## Further changes +* The clock signal was renamed from `clk` to `clock` in Chisel3. +* Change `getWidth()` to `getWidth` + +## Packaging +Chisel3 is implemented as several packages. +The core DSL is differentiated from utility or library classes and objects, testers, and interpreters. +The prime components of the Chisel3 front end (the DSL and library objects) are: +* coreMacros - source locators provide Chisel line numbers for `firrtl` detected errors, +* chiselFrontend - main DSL components, +* chisel3 - compiler driver, interface packages, compatibility layer. + +Due to the wonders of `sbt`, you need only declare a dependency on the chisel3 package, and the others will be downloaded as required. + +The `firrtl` compiler is distributed as a separate package, and release versions will also be downloaded automatically as required. +If you choose to integrate the compiler into your own toolchain, or you're working with the development (master) branch of chisel3, you should clone the [firrtl](https://github.com/ucb-bar/firrtl) repo +and follow the instructions for installing the `firrtl` compiler. + +The testers in Chisel3 are distributed as a separate package. +If you intend to use them in your tests, you will either need to clone the [chisel-testers](https://github.com/ucb-bar/chisel-testers) repo +or declare a dependency on the published version of the package. +See the `build.sbt` file in either the [chisel-template](https://github.com/ucb-bar/chisel-template) or [chisel-tutorial](https://github.com/ucb-bar/chisel-tutorial) +repos for examples of the latter. + +## Simulation +Chisel2 was capable of directly generating a `C++` simulation from the Chisel code, or a harness for use with a `vcs` simulation. +Chisel3 relies on [verilator](http://www.veripool.org/wiki/verilator) to generate the `C++` simulation from the Verilog output of `firrtl`. +See the [Chisel3 README](https://github.com/ucb-bar/chisel3) for directions on installing `verilator`. + +## Compile Options and Front End Checks (Strict vs. NotStrict) +Chisel3 introduces a formal specification for hardware circuit graphs: FIRRTL, +and Chisel3 itself (the Scala library implementing the Chisel DSL), is a relatively thin front end that generates FIRRTL. +Since the `firrtl` parser needs to validate FIRRTL input, most of the checks that were performed in Chisel2 were eliminated +from the initial Chisel3 front end (the DRY principle). + +However, this does impact the ability to provide detailed messages for error conditions that could be detected in the Chisel3 +front end. The decision was made to optionally enable stricter error checking (for connections and the use of raw types versus +hardware objects), based on specific imports. +This allows designs to move from less strict front end checks (largely compatible with Chisel2), to stricter checking, +on a file by file basis, by adjusting specific import statements. + +```scala + import chisel3.core.ExplicitCompileOptions.Strict +``` + +enables stricter connection and usage checks, while + +```scala + import chisel3.core.ExplicitCompileOptions.NotStrict +``` + +defers these checks to the `firrtl` compiler. + +By default, the `Chisel` compatibility layer, invoked by: + +```scala + import Chisel._ +``` + +implicitly defines the compile options as `chisel3.core.ExplicitCompileOptions.NotStrict` + +whereas the Chisel3 package, invoked by: + +```scala + import chisel3._ +``` + +implicitly defines the compile options as `chisel3.core.ExplicitCompileOptions.Strict` + +Again, these implicit compile options definitions may be overridden by explicit imports. + +Currently, the specific error checks (found in [CompileOptions.scala](https://github.com/ucb-bar/chisel3/blob/master/chiselFrontend/src/main/scala/chisel3/core/CompileOptions.scala)) are: + +```scala + trait CompileOptions { + // Should Bundle 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). + val declaredTypeMustBeUnbound: Boolean + // Module IOs should be wrapped in an IO() to define their bindings before the reset of the module is defined. + val requireIOWrap: Boolean + // 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. + val dontAssumeDirectionality: Boolean + // Issue a deprecation warning if Data.{flip, asInput,asOutput} is used + // instead of Flipped, Input, or Output. + val deprecateOldDirectionMethods: Boolean + // Check that referenced Data have actually been declared. + val checkSynthesizable: Boolean + } +``` + +`chisel3.core.ExplicitCompileOptions.Strict` sets all CompileOptions fields to true and +`chisel3.core.ExplicitCompileOptions.NotStrict` sets them all to false. +Clients are free to define their own settings for these options. +Examples may be found in the test [CompileOptionsSpec](https://github.com/ucb-bar/chisel3/blob/master/src/test/scala/chiselTests/CompileOptionsTest.scala) diff --git a/docs/src/appendix/experimental-features.md b/docs/src/appendix/experimental-features.md new file mode 100644 index 00000000..ba1a028d --- /dev/null +++ b/docs/src/appendix/experimental-features.md @@ -0,0 +1,138 @@ +--- +layout: docs +title: "Experimental Features" +section: "chisel3" +--- + +Chisel has a number of new features that are worth checking out. This page is an informal list of these features and projects. + +### FixedPoint +FixedPoint numbers are basic *Data* type along side of UInt, SInt, etc. Most common math and logic operations +are supported. Chisel allows both the width and binary point to be inferred by the Firrtl compiler which can simplify +circuit descriptions. See [FixedPointSpec](https://github.com/freechipsproject/chisel3/tree/master/src/test/scala/chiselTests/FixedPointSpec.scala) + +### Module Variants +The standard Chisel *Module* requires a `val io = IO(...)`, the experimental package introduces several +new ways of defining Modules +- BaseModule: no contents, instantiable +- BlackBox extends BaseModule +- UserDefinedModule extends BaseModule: this module can contain Chisel RTL. No default clock or reset lines. No default IO. - User should be able to specify non-io ports, ideally multiple of them. +- ImplicitModule extends UserModule: has clock, reset, and io, essentially current Chisel Module. +- RawModule: will be the user-facing version of UserDefinedModule +- Module: type-aliases to ImplicitModule, the user-facing version of ImplicitModule. + +### Bundle Literals + +Bundle literals can be constructed via an experimental import: + +```scala mdoc +import chisel3._ +import chisel3.experimental.BundleLiterals._ + +class MyBundle extends Bundle { + val a = UInt(8.W) + val b = Bool() +} + +class Example extends RawModule { + val out = IO(Output(new MyBundle)) + out := (new MyBundle).Lit(_.a -> 8.U, _.b -> true.B) +} +``` + +```scala mdoc:verilog +chisel3.stage.ChiselStage.emitVerilog(new Example) +``` + +Partial specification is allowed, defaulting any unconnected fields to 0 (regardless of type). + +```scala mdoc +class Example2 extends RawModule { + val out = IO(Output(new MyBundle)) + out := (new MyBundle).Lit(_.b -> true.B) +} +``` + +```scala mdoc:verilog +chisel3.stage.ChiselStage.emitVerilog(new Example2) +``` + +Bundle literals can also be nested arbitrarily. + +```scala mdoc +class ChildBundle extends Bundle { + val foo = UInt(8.W) +} + +class ParentBundle extends Bundle { + val a = UInt(8.W) + val b = new ChildBundle +} + +class Example3 extends RawModule { + val out = IO(Output(new ParentBundle)) + out := (new ParentBundle).Lit(_.a -> 123.U, _.b -> (new ChildBundle).Lit(_.foo -> 42.U)) +} +``` + +```scala mdoc:verilog +chisel3.stage.ChiselStage.emitVerilog(new Example3) +``` + +Vec literals are not yet supported. + +### Interval Type + +**Intervals** are a new experimental numeric type that comprises UInt, SInt and FixedPoint numbers. +It augments these types with range information, i.e. upper and lower numeric bounds. +This information can be used to exercise tighter programmatic control over the ultimate widths of +signals in the final circuit. The **Firrtl** compiler can infer this range information based on +operations and earlier values in the circuit. Intervals support all the ordinary bit and arithmetic operations +associated with UInt, SInt, and FixedPoint and adds the following methods for manipulating the range of +a **source** Interval with the IntervalRange of **target** Interval + +#### Clip -- Fit the value **source** into the IntervalRange of **target**, saturate if out of bounds +The clip method applied to an interval creates a new interval based on the argument to clip, +and constructs the necessary hardware so that the source Interval's value will be mapped into the new Interval. +Values that are outside the result range will be pegged to either maximum or minimum of result range as appropriate. + +> Generates necessary hardware to clip values, values greater than range are set to range.high, values lower than range are set to range min. + +#### Wrap -- Fit the value **source** into the IntervalRange of **target**, wrapping around if out of bounds +The wrap method applied to an interval creates a new interval based on the argument to wrap, +and constructs the necessary +hardware so that the source Interval's value will be mapped into the new Interval. +Values that are outside the result range will be wrapped until they fall within the result range. + +> Generates necessary hardware to wrap values, values greater than range are set to range.high, values lower than range are set to range min. + +> Does not handle out of range values that are less than half the minimum or greater than twice maximum + +#### Squeeze -- Fit the value **source** into the smallest IntervalRange based on source and target. +The squeeze method applied to an interval creates a new interval based on the argument to clip, the two ranges must overlap +behavior of squeeze with inputs outside of the produced range is undefined. + +> Generates no hardware, strictly a sizing operation + +##### Range combinations + +| Condition | A.clip(B) | A.wrap(B) | A.squeeze(B) | +| --------- | --------------- | --------------- | --------------- | +| A === B | max(Alo, Blo), min(Ahi, Bhi) | max(Alo, Blo), min(Ahi, Bhi) | max(Alo, Blo), min(Ahi, Bhi) | +| A contains B | max(Alo, Blo), min(Ahi, Bhi) | max(Alo, Blo), min(Ahi, Bhi) | max(Alo, Blo), min(Ahi, Bhi) | +| B contains A | max(Alo, Blo), min(Ahi, Bhi) | max(Alo, Blo), min(Ahi, Bhi) | max(Alo, Blo), min(Ahi, Bhi) | +| A min < B min, A max in B | max(Alo, Blo), min(Ahi, Bhi) | max(Alo, Blo), min(Ahi, Bhi) | max(Alo, Blo), min(Ahi, Bhi) | +| A min in B, A max > B max | max(Alo, Blo), min(Ahi, Bhi) | max(Alo, Blo), min(Ahi, Bhi) | max(Alo, Blo), min(Ahi, Bhi) | +| A strictly less than B | error | error | error | +| A strictly greater than B | error | error | error | + + +#### Applying binary point operators to an Interval + +Consider a Interval with a binary point of 3: aaa.bbb + +| operation | after operation | binary point | lower | upper | meaning | +| --------- | --------------- | ------------ | ----- | ----- | ------- | +| setBinaryPoint(2) | aaa.bb | 2 | X | X | set the precision | +| shiftLeftBinaryPoint(2) | a.aabbb | 5 | X | X | increase the precision | +| shiftRighBinaryPoint(2) | aaaa.b | 1 | X | X | reduce the precision | diff --git a/docs/src/appendix/upgrading-from-scala-2-11.md b/docs/src/appendix/upgrading-from-scala-2-11.md new file mode 100644 index 00000000..26e2d252 --- /dev/null +++ b/docs/src/appendix/upgrading-from-scala-2-11.md @@ -0,0 +1,88 @@ +--- +layout: docs +title: "Upgrading From Scala 2.11" +section: "chisel3" +redirect_from: + - /chisel3/upgrading-from-scala-2-11.html +--- + + +```scala mdoc:invisible +import chisel3._ +``` + + +## Upgrading From Scala 2.11 to 2.12 + +As the latest (and probably last) release of Scala 2.11 (2.11.12) was released on 2 November 2017, the time has come to deprecate support for Scala 2.11. +Chisel 3.4 is the last version of Chisel that will support Scala 2.11, so users should upgrade to Scala 2.12 +This document is intended to help guide Chisel users through this process; both the "Why?" and the "How?". + +### Scala Versioning + + + +Scala versions have the following structure: `2.X.Y` where `X` is the _major version_ and `Y` is the _minor version_. +Note that while we keep the leading `2` constant, there is a project, [Dotty](https://dotty.epfl.ch/), that is slated to become Scala 3. + +Scala maintains both source and binary compatiblity between minor versions, but not between major versions. +Binary compatibility is defined at the level of the Java Byte Code (the `.class` or `.jar` files compiled from `.scala`). +This means that Scala projects that support multiple major versions of Scala must be compiled and published for each supported version. +When publishing artifacts to Maven repositories, this manifests as an appendix on the _Artifact ID_. +Taking Chisel v3.3.2 as an example, the "Artifact ID" is ["chisel3_2.12"](https://search.maven.org/artifact/edu.berkeley.cs/chisel3_2.12) +for Scala 2.12, and ["chisel3_2.11"](https://search.maven.org/artifact/edu.berkeley.cs/chisel3_2.11) for Scala 2.11. + +For more information, see the documentation on the Scala website: +* [Binary Compatibility of Scala Releases](https://docs.scala-lang.org/overviews/core/binary-compatibility-of-scala-releases.html) +* [Binary Compatibility for Library Authoers](https://docs.scala-lang.org/overviews/core/binary-compatibility-for-library-authors.html) + + +### How to Upgrade + +For most users, this is as simple as changing the `scalaVersion` field in your `build.sbt`: +```scala +scalaVersion := "2.11.12" +``` +Becomes +```scala +scalaVersion := "2.12.12" +``` +Now, the next time you run SBT, it will be using the Scala 2.12 version of Chisel 3 (as well as any other dependencies you have). + +### Common Issues + +As mentioned in the [previous section](#scala-versioning), Scala does *not* maintain source compatibilty between major versions. +Put another way, sometimes they break things in backwards incompatible ways. +This section includes some common issues that Chisel users run into and how to fix them. + +For complete information about changes, please see the [release notes for Scala 2.12.0](https://www.scala-lang.org/news/2.12.0/). + +#### Value is not a member of chisel3.Bundle + +The most common problem for Chisel users upgrading from Scala 2.11 to 2.12 is a change in Scala type inference. +This usually occurs in the context of `io` `Bundles` in `Modules`, given: +```scala mdoc:silent +class Foo extends Module { + val io = IO(new Bundle { + val in = Input(Bool()) + val out = Output(Bool()) + }) + + io.out := ~io.in +} +``` +You may see an error that says somethign like "value out is not a member of chisel3.Bundle": +``` +[error] /workspace/src/main/scala/gcd/Foo.scala:9:6: value out is not a member of chisel3.Bundle +[error] io.out := ~io.in +[error] ^ +[error] /workspace/src/main/scala/gcd/Foo.scala:9:17: value in is not a member of chisel3.Bundle +[error] io.out := ~io.in +[error] ^ +[error] two errors found +``` +This can be worked around by adding `-Xsource:2.11` to your `scalacOptions`. +This is most commonly set in your `build.sbt`. +For an example, see the [chisel-template's build.sbt](https://github.com/freechipsproject/chisel-template/blob/11f6ca470120908d167cb8dc3241953eb31d0acb/build.sbt#L10). + + diff --git a/docs/src/explanations/blackboxes.md b/docs/src/explanations/blackboxes.md index a8d5fe03..4ecd1ea0 100644 --- a/docs/src/explanations/blackboxes.md +++ b/docs/src/explanations/blackboxes.md @@ -9,7 +9,7 @@ for hardware constructs that cannot be described in Chisel and for connecting to Modules defined as a `BlackBox` will be instantiated in the generated Verilog, but no code will be generated to define the behavior of module. -Unlike Module, `BlackBox` has no implicit clock and reset. +Unlike Module, `BlackBox` has no implicit clock and reset. `BlackBox`'s clock and reset ports must be explicitly declared and connected to input signals. Ports declared in the IO Bundle will be generated with the requested name (ie. no preceding `io_`). @@ -34,7 +34,7 @@ class IBUFDS extends BlackBox(Map("DIFF_TERM" -> "TRUE", } class Top extends Module { - val io = IO(new Bundle{}) + val io = IO(new Bundle {}) val ibufds = Module(new IBUFDS) // connecting one of IBUFDS's input clock ports to Top's clock signal ibufds.io.I := clock @@ -52,12 +52,14 @@ IBUFDS #(.DIFF_TERM("TRUE"), .IOSTANDARD("DEFAULT")) ibufds ( ``` ### Providing Implementations for Blackboxes + Chisel provides the following ways of delivering the code underlying the blackbox. Consider the following blackbox that adds two real numbers together. The numbers are represented in chisel3 as 64-bit unsigned integers. + ```scala mdoc:silent:reset import chisel3._ class BlackBoxRealAdd extends BlackBox { - val io = IO(new Bundle() { + val io = IO(new Bundle { val in1 = Input(UInt(64.W)) val in2 = Input(UInt(64.W)) val out = Output(UInt(64.W)) @@ -66,6 +68,7 @@ class BlackBoxRealAdd extends BlackBox { ``` The implementation is described by the following verilog + ```verilog module BlackBoxRealAdd( input [63:0] in1, @@ -73,39 +76,43 @@ module BlackBoxRealAdd( output reg [63:0] out ); always @* begin - out <= $realtobits($bitstoreal(in1) + $bitstoreal(in2)); + out <= $realtobits($bitstoreal(in1) + $bitstoreal(in2)); end endmodule ``` ### Blackboxes with Verilog in a Resource File -In order to deliver the verilog snippet above to the backend simulator, chisel3 provides the following tools based on the chisel/firrtl [annotation system](../explanations/annotations). Add the trait ```HasBlackBoxResource``` to the declaration, and then call a function in the body to say where the system can find the verilog. The Module now looks like -```mdoc scala:silent:reset + +In order to deliver the verilog snippet above to the backend simulator, chisel3 provides the following tools based on the chisel/firrtl [annotation system](../explanations/annotations). Add the trait `HasBlackBoxResource` to the declaration, and then call a function in the body to say where the system can find the verilog. The Module now looks like + +```scala mdoc:silent:reset +import chisel3._ +import chisel3.util.HasBlackBoxResource + class BlackBoxRealAdd extends BlackBox with HasBlackBoxResource { - val io = IO(new Bundle() { + val io = IO(new Bundle { val in1 = Input(UInt(64.W)) val in2 = Input(UInt(64.W)) val out = Output(UInt(64.W)) }) - setResource("/real_math.v") + addResource("/real_math.v") } ``` -The verilog snippet above gets put into a resource file names ```real_math.v```. What is a resource file? It comes from + +The verilog snippet above gets put into a resource file names `real_math.v`. What is a resource file? It comes from a java convention of keeping files in a project that are automatically included in library distributions. In a typical chisel3 project, see [chisel-template](https://github.com/ucb-bar/chisel-template), this would be a directory in the - source hierarchy -``` -src/main/resources/real_math.v -``` + source hierarchy: `src/main/resources/real_math.v`. ### Blackboxes with In-line Verilog -It is also possible to place this verilog directly in the scala source. Instead of ```HasBlackBoxResource``` use - ```HasBlackBoxInline``` and instead of ```setResource``` use ```setInline```. The code will look like this. +It is also possible to place this verilog directly in the scala source. Instead of `HasBlackBoxResource` use + `HasBlackBoxInline` and instead of `setResource` use `setInline`. The code will look like this. + ```scala mdoc:silent:reset import chisel3._ import chisel3.util.HasBlackBoxInline class BlackBoxRealAdd extends BlackBox with HasBlackBoxInline { - val io = IO(new Bundle() { + val io = IO(new Bundle { val in1 = Input(UInt(64.W)) val in2 = Input(UInt(64.W)) val out = Output(UInt(64.W)) @@ -123,15 +130,16 @@ class BlackBoxRealAdd extends BlackBox with HasBlackBoxInline { """.stripMargin) } ``` -This technique will copy the inline verilog into the target directory under the name ```BlackBoxRealAdd.v``` + +This technique will copy the inline verilog into the target directory under the name `BlackBoxRealAdd.v` ### Under the Hood This mechanism of delivering verilog content to the testing backends is implemented via chisel/firrtl annotations. The -two methods, inline and resource, are two kinds of annotations that are created via the ```setInline``` and -```setResource``` methods calls. Those annotations are passed through to the chisel-testers which in turn passes them +two methods, inline and resource, are two kinds of annotations that are created via the `setInline` and +`setResource` methods calls. Those annotations are passed through to the chisel-testers which in turn passes them on to firrtl. The default firrtl verilog compilers have a pass that detects the annotations and moves the files or inline test into the build directory. For each unique file added, the transform adds a line to a file -black_box_verilog_files.f, this file is added to the command line constructed for verilator or vcs to inform them where +`black_box_verilog_files.f`, this file is added to the command line constructed for verilator or vcs to inform them where to look. The [dsptools project](https://github.com/ucb-bar/dsptools) is a good example of using this feature to build a real number simulation tester based on black boxes. @@ -144,4 +152,4 @@ construct scala implementations of the black boxes. The scala implementation co passed down to the interpreter by the execution harness. The interpreter is a scala simulation tester. Once again the dsptools project uses this mechanism and is a good place to look at it. > It is planned that the BlackBoxFactory will be replaced by integration with the annotation based blackbox methods ->stuff soon. +> stuff soon. diff --git a/docs/src/explanations/bundles-and-vecs.md b/docs/src/explanations/bundles-and-vecs.md index dcac31cd..bac9393a 100644 --- a/docs/src/explanations/bundles-and-vecs.md +++ b/docs/src/explanations/bundles-and-vecs.md @@ -3,14 +3,12 @@ layout: docs title: "Bundles and Vecs" section: "chisel3" --- -``` - -``` `Bundle` and `Vec` are classes that allow the user to expand the set of Chisel datatypes with aggregates of other types. Bundles group together several named fields of potentially different types into a coherent unit, much like a `struct` in C. Users define their own bundles by defining a class as a subclass of `Bundle`. + ```scala mdoc:silent import chisel3._ class MyFloat extends Bundle { @@ -25,24 +23,12 @@ class ModuleWithFloatWire extends RawModule { } ``` -> Currently, there is no way to create a bundle literal like ```8.U``` for ```UInt```s. Therefore, in order to create ->literals for bundles, we must declare a [[wire|Combinational-Circuits#wires]] of that bundle type, and then assign ->values to it. We are working on a way to declare bundle literals without requiring the creation of a Wire node and ->assigning to it. +You can create literal Bundles using the experimental [Bundle Literals](../appendix/experimental-features#bundle-literals) feature. -```scala mdoc:silent -class ModuleWithFloatConstant extends RawModule { - // Floating point constant. - val floatConst = Wire(new MyFloat) - floatConst.sign := true.B - floatConst.exponent := 10.U - floatConst.significand := 128.U -} -``` - -A Scala convention is to capitalize the name of new classes and we suggest you follow that convention in Chisel too. +Scala convention is to name classes using UpperCamelCase, and we suggest you follow that convention in your Chisel code. Vecs create an indexable vector of elements, and are constructed as follows: + ```scala mdoc:silent class ModuleWithVec extends RawModule { // Vector of 5 23-bit signed integers. @@ -63,6 +49,7 @@ superclass, `Data`. Every object that ultimately inherits from Bundles and Vecs can be arbitrarily nested to build complex data structures: + ```scala mdoc:silent class BigBundle extends Bundle { // Vector of 5 23-bit signed integers. @@ -152,6 +139,7 @@ Note that in the vast majority of cases, **this is not required** as Chisel can automatically. Here is an example of a parametrized bundle (`ExampleBundle`) that features a custom `cloneType`. + ```scala mdoc:silent class ExampleBundle(a: Int, b: Int) extends Bundle { val foo = UInt(a.W) diff --git a/docs/src/wiki-deprecated/chisel3-vs-chisel2.md b/docs/src/wiki-deprecated/chisel3-vs-chisel2.md deleted file mode 100644 index bfd20348..00000000 --- a/docs/src/wiki-deprecated/chisel3-vs-chisel2.md +++ /dev/null @@ -1,203 +0,0 @@ ---- -layout: docs -title: "Chisel3 vs. Chisel2" -section: "chisel3" ---- - -# Chisel3 vs Chisel2 - -## Chisel2 Migration -For those moving from Chisel2, there were some backwards incompatible changes -and your RTL needs to be modified to work with Chisel3. The required -modifications are: - - - Wire declaration style: - ```scala - val wire = UInt(width = 15) - ``` - becomes (in Chisel3): - ```scala - val wire = Wire(UInt(15.W)) - ``` - - - I/O declaration style: - ```scala - val done = Bool(OUTPUT) - ``` - becomes (in Chisel3): - ```scala - val wire = Output(Bool()) - ``` - - - Sequential memories: - ```scala - val addr = Reg(UInt()) - val mem = Mem(UInt(8.W), 1024, seqRead = true) - val dout = when(enable) { mem(addr) } - ``` - becomes (in Chisel3): - ```scala - val addr = UInt() - val mem = SyncReadMem(1024, UInt(8.W)) - val dout = mem.read(addr, enable) - ``` - - Notice the address register is now internal to the SyncReadMem(), but the data - will still return on the subsequent cycle. - - - Generating Verilog with - ```scala - object Hello { - def main(args: Array[String]): Unit = { - chiselMain(Array("--backend", "v"), () => Module(new Hello())) - } - } - ``` - becomes (in Chisel3): - ```scala - object Hello { - def main(args: Array[String]): Unit = { - chisel3.Driver.execute(Array[String](), () => new Hello()) - } - } - ``` - - - Package changes: - - Chisel.log2Ceil -> chisel3.util.log2Ceil - - BitPat - - Decoupled is also in chisel3.util - -Please refer to the [Chisel3 compatibility section](https://github.com/ucb-bar/chisel#chisel3) -for instructions on preparing your Chisel2 designs for Chisel3. - -## Deprecated Usage -* `Vec(Reg)` should be replaced with `Reg(Vec)`, -* type-only vals (no associated data) must be wrapped in a `Wire()` if they will be the destination of a wiring operation (":=" or " < >"), -* masked bit patterns ('b??') should be created using BitPat(), not UInt() or Bits(), -* the `clone` method required for parameterized Bundles has been renamed `cloneType`, -* the con and alt inputs to a Mux must be type-compatible - both signed or both unsigned, -* bulk-connection to a node that has been procedurally assigned-to is illegal, -* `!=` is deprecated, use `=/=` instead, -* use `SyncReadMem(...)` instead of `Mem(..., seqRead)`, -* use `SyncReadMem(n:Int, out: => T)` instead of `SyncReadMem(out: => T, n:Int)`, -* use `SyncReadMem(...)` instead of `SeqMem(...)`, -* use `Mem(n:Int, t:T)` instead of `Mem(out:T, n:Int)`, -* use `Vec(n:Int, gen: => T)` instead of `Vec(gen: => T, n:Int)`, -* module io's must be wrapped in `IO()`. -* The methods `asInput`, `asOutput`, and `flip` should be replaced by the `Input()`, `Output()`, and `Flipped()` object apply methods. - -## Unsupported constructs -* `Mem(..., orderedWrites)` is no longer supported, -* masked writes are only supported for `Mem[Vec[_]]`, -* Chisel3 Vecs must all have the same type, unlike with Chisel2. Use `MixedVec` (see [Bundles and Vecs](../explanations/bundles-and-vecs)) for Vecs where the elements are of different types. -* connections between `UInt` and `SInt` are illegal. -* the `Node` class and object no longer exist (the class should have been private in Chisel2) -* `printf()` is defined in the Chisel object and produces simulation printf()'s. -To use the Scala `Predef.printf()`, you need to qualify it with `Predef`. -* in Chisel2, bulk-connects `<>` with unconnected source components do not update connections from the unconnected components. -** In Chisel3, bulk-connects strictly adhere to last connection semantics and unconnected OUTPUTs will be connected to INPUTs resulting in the assignment of random values to those inputs. -* In Chisel3, adding hardware inside `BlackBox` for simulation is no longer supported. (#289) -* `ChiselError` is gone - * Change `ChiselError.error("error msg")` to `throw new Error("error msg")` - * Change `ChiselError.info("info msg")` to `println("info msg")` -* In Chisel3, subword assignments are not supported. [Alternative constructions exist](https://github.com/freechipsproject/chisel3/wiki/Cookbook#how-do-i-do-subword-assignment-assign-to-some-bits-in-a-uint) in Chisel3. - -## Further changes -* The clock signal was renamed from `clk` to `clock` in Chisel3. -* Change `getWidth()` to `getWidth` - -## Packaging -Chisel3 is implemented as several packages. -The core DSL is differentiated from utility or library classes and objects, testers, and interpreters. -The prime components of the Chisel3 front end (the DSL and library objects) are: -* coreMacros - source locators provide Chisel line numbers for `firrtl` detected errors, -* chiselFrontend - main DSL components, -* chisel3 - compiler driver, interface packages, compatibility layer. - -Due to the wonders of `sbt`, you need only declare a dependency on the chisel3 package, and the others will be downloaded as required. - -The `firrtl` compiler is distributed as a separate package, and release versions will also be downloaded automatically as required. -If you choose to integrate the compiler into your own toolchain, or you're working with the development (master) branch of chisel3, you should clone the [firrtl](https://github.com/ucb-bar/firrtl) repo -and follow the instructions for installing the `firrtl` compiler. - -The testers in Chisel3 are distributed as a separate package. -If you intend to use them in your tests, you will either need to clone the [chisel-testers](https://github.com/ucb-bar/chisel-testers) repo -or declare a dependency on the published version of the package. -See the `build.sbt` file in either the [chisel-template](https://github.com/ucb-bar/chisel-template) or [chisel-tutorial](https://github.com/ucb-bar/chisel-tutorial) -repos for examples of the latter. - -## Simulation -Chisel2 was capable of directly generating a `C++` simulation from the Chisel code, or a harness for use with a `vcs` simulation. -Chisel3 relies on [verilator](http://www.veripool.org/wiki/verilator) to generate the `C++` simulation from the Verilog output of `firrtl`. -See the [Chisel3 README](https://github.com/ucb-bar/chisel3) for directions on installing `verilator`. - -## Compile Options and Front End Checks (Strict vs. NotStrict) -Chisel3 introduces a formal specification for hardware circuit graphs: FIRRTL, -and Chisel3 itself (the Scala library implementing the Chisel DSL), is a relatively thin front end that generates FIRRTL. -Since the `firrtl` parser needs to validate FIRRTL input, most of the checks that were performed in Chisel2 were eliminated -from the initial Chisel3 front end (the DRY principle). - -However, this does impact the ability to provide detailed messages for error conditions that could be detected in the Chisel3 -front end. The decision was made to optionally enable stricter error checking (for connections and the use of raw types versus -hardware objects), based on specific imports. -This allows designs to move from less strict front end checks (largely compatible with Chisel2), to stricter checking, -on a file by file basis, by adjusting specific import statements. - -```scala - import chisel3.core.ExplicitCompileOptions.Strict -``` - -enables stricter connection and usage checks, while - -```scala - import chisel3.core.ExplicitCompileOptions.NotStrict -``` - -defers these checks to the `firrtl` compiler. - -By default, the `Chisel` compatibility layer, invoked by: - -```scala - import Chisel._ -``` - -implicitly defines the compile options as `chisel3.core.ExplicitCompileOptions.NotStrict` - -whereas the Chisel3 package, invoked by: - -```scala - import chisel3._ -``` - -implicitly defines the compile options as `chisel3.core.ExplicitCompileOptions.Strict` - -Again, these implicit compile options definitions may be overridden by explicit imports. - -Currently, the specific error checks (found in [CompileOptions.scala](https://github.com/ucb-bar/chisel3/blob/master/chiselFrontend/src/main/scala/chisel3/core/CompileOptions.scala)) are: - -```scala - trait CompileOptions { - // Should Bundle 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). - val declaredTypeMustBeUnbound: Boolean - // Module IOs should be wrapped in an IO() to define their bindings before the reset of the module is defined. - val requireIOWrap: Boolean - // 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. - val dontAssumeDirectionality: Boolean - // Issue a deprecation warning if Data.{flip, asInput,asOutput} is used - // instead of Flipped, Input, or Output. - val deprecateOldDirectionMethods: Boolean - // Check that referenced Data have actually been declared. - val checkSynthesizable: Boolean - } -``` - -`chisel3.core.ExplicitCompileOptions.Strict` sets all CompileOptions fields to true and -`chisel3.core.ExplicitCompileOptions.NotStrict` sets them all to false. -Clients are free to define their own settings for these options. -Examples may be found in the test [CompileOptionsSpec](https://github.com/ucb-bar/chisel3/blob/master/src/test/scala/chiselTests/CompileOptionsTest.scala) diff --git a/docs/src/wiki-deprecated/experimental-features.md b/docs/src/wiki-deprecated/experimental-features.md deleted file mode 100644 index d36b2946..00000000 --- a/docs/src/wiki-deprecated/experimental-features.md +++ /dev/null @@ -1,119 +0,0 @@ ---- -layout: docs -title: "Experimental Features" -section: "chisel3" ---- - -Chisel has a number of new features that are worth checking out. This page is an informal list of these features and projects. - -### FixedPoint -FixedPoint numbers are basic *Data* type along side of UInt, SInt, etc. Most common math and logic operations -are supported. Chisel allows both the width and binary point to be inferred by the Firrtl compiler which can simplify -circuit descriptions. See [FixedPointSpec](https://github.com/freechipsproject/chisel3/tree/master/src/test/scala/chiselTests/FixedPointSpec.scala) - -### Module Variants -The standard Chisel *Module* requires a ```val io = IO(...)```, the experimental package introduces several -new ways of defining Modules -- BaseModule: no contents, instantiable -- BlackBox extends BaseModule -- UserDefinedModule extends BaseModule: this module can contain Chisel RTL. No default clock or reset lines. No default IO. - User should be able to specify non-io ports, ideally multiple of them. -- ImplicitModule extends UserModule: has clock, reset, and io, essentially current Chisel Module. -- RawModule: will be the user-facing version of UserDefinedModule -- Module: type-aliases to ImplicitModule, the user-facing version of ImplicitModule. - -### Bundle Literals - -Chisel 3.2 introduces an experimental mechanism for Bundle literals in #820, but this feature is largely incomplete and not ready for user code yet. The following is provided as documentation for library writers who want to take a stab at using this mechanism for their library's bundles. - -```mdoc scala -class MyBundle extends Bundle { - val a = UInt(8.W) - val b = Bool() - - // Bundle literal constructor code, which will be auto-generated using macro annotations in - // the future. - import chisel3.core.BundleLitBinding - import chisel3.internal.firrtl.{ULit, Width} - - // Full bundle literal constructor - def Lit(aVal: UInt, bVal: Bool): MyBundle = { - val clone = cloneType - clone.selfBind(BundleLitBinding(Map( - clone.a -> litArgOfBits(aVal), - clone.b -> litArgOfBits(bVal) - ))) - clone - } - - // Partial bundle literal constructor - def Lit(aVal: UInt): MyBundle = { - val clone = cloneType - clone.selfBind(BundleLitBinding(Map( - clone.a -> litArgOfBits(aVal) - ))) - clone - } -} -``` - -Example usage: - -```scala -val outsideBundleLit = (new MyBundle).Lit(42.U, true.B) -``` - -### Interval Type - -**Intervals** are a new experimental numeric type that comprises UInt, SInt and FixedPoint numbers. -It augments these types with range information, i.e. upper and lower numeric bounds. -This information can be used to exercise tighter programmatic control over the ultimate widths of -signals in the final circuit. The **Firrtl** compiler can infer this range information based on -operations and earlier values in the circuit. Intervals support all the ordinary bit and arithmetic operations -associated with UInt, SInt, and FixedPoint and adds the following methods for manipulating the range of -a **source** Interval with the IntervalRange of **target** Interval - -#### Clip -- Fit the value **source** into the IntervalRange of **target**, saturate if out of bounds -The clip method applied to an interval creates a new interval based on the argument to clip, -and constructs the necessary hardware so that the source Interval's value will be mapped into the new Interval. -Values that are outside the result range will be pegged to either maximum or minimum of result range as appropriate. - -> Generates necessary hardware to clip values, values greater than range are set to range.high, values lower than range are set to range min. - -#### Wrap -- Fit the value **source** into the IntervalRange of **target**, wrapping around if out of bounds -The wrap method applied to an interval creates a new interval based on the argument to wrap, -and constructs the necessary -hardware so that the source Interval's value will be mapped into the new Interval. -Values that are outside the result range will be wrapped until they fall within the result range. - -> Generates necessary hardware to wrap values, values greater than range are set to range.high, values lower than range are set to range min. - -> Does not handle out of range values that are less than half the minimum or greater than twice maximum - -#### Squeeze -- Fit the value **source** into the smallest IntervalRange based on source and target. -The squeeze method applied to an interval creates a new interval based on the argument to clip, the two ranges must overlap -behavior of squeeze with inputs outside of the produced range is undefined. - -> Generates no hardware, strictly a sizing operation - -##### Range combinations - -| Condition | A.clip(B) | A.wrap(B) | A.squeeze(B) | -| --------- | --------------- | --------------- | --------------- | -| A === B | max(Alo, Blo), min(Ahi, Bhi) | max(Alo, Blo), min(Ahi, Bhi) | max(Alo, Blo), min(Ahi, Bhi) | -| A contains B | max(Alo, Blo), min(Ahi, Bhi) | max(Alo, Blo), min(Ahi, Bhi) | max(Alo, Blo), min(Ahi, Bhi) | -| B contains A | max(Alo, Blo), min(Ahi, Bhi) | max(Alo, Blo), min(Ahi, Bhi) | max(Alo, Blo), min(Ahi, Bhi) | -| A min < B min, A max in B | max(Alo, Blo), min(Ahi, Bhi) | max(Alo, Blo), min(Ahi, Bhi) | max(Alo, Blo), min(Ahi, Bhi) | -| A min in B, A max > B max | max(Alo, Blo), min(Ahi, Bhi) | max(Alo, Blo), min(Ahi, Bhi) | max(Alo, Blo), min(Ahi, Bhi) | -| A strictly less than B | error | error | error | -| A strictly greater than B | error | error | error | - - -#### Applying binary point operators to an Interval - -Consider a Interval with a binary point of 3: aaa.bbb - -| operation | after operation | binary point | lower | upper | meaning | -| --------- | --------------- | ------------ | ----- | ----- | ------- | -| setBinaryPoint(2) | aaa.bb | 2 | X | X | set the precision | -| shiftLeftBinaryPoint(2) | a.aabbb | 5 | X | X | increase the precision | -| shiftRighBinaryPoint(2) | aaaa.b | 1 | X | X | reduce the precision | diff --git a/docs/src/wiki-deprecated/upgrading-from-scala-2-11.md b/docs/src/wiki-deprecated/upgrading-from-scala-2-11.md deleted file mode 100644 index 26e2d252..00000000 --- a/docs/src/wiki-deprecated/upgrading-from-scala-2-11.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -layout: docs -title: "Upgrading From Scala 2.11" -section: "chisel3" -redirect_from: - - /chisel3/upgrading-from-scala-2-11.html ---- - - -```scala mdoc:invisible -import chisel3._ -``` - - -## Upgrading From Scala 2.11 to 2.12 - -As the latest (and probably last) release of Scala 2.11 (2.11.12) was released on 2 November 2017, the time has come to deprecate support for Scala 2.11. -Chisel 3.4 is the last version of Chisel that will support Scala 2.11, so users should upgrade to Scala 2.12 -This document is intended to help guide Chisel users through this process; both the "Why?" and the "How?". - -### Scala Versioning - - - -Scala versions have the following structure: `2.X.Y` where `X` is the _major version_ and `Y` is the _minor version_. -Note that while we keep the leading `2` constant, there is a project, [Dotty](https://dotty.epfl.ch/), that is slated to become Scala 3. - -Scala maintains both source and binary compatiblity between minor versions, but not between major versions. -Binary compatibility is defined at the level of the Java Byte Code (the `.class` or `.jar` files compiled from `.scala`). -This means that Scala projects that support multiple major versions of Scala must be compiled and published for each supported version. -When publishing artifacts to Maven repositories, this manifests as an appendix on the _Artifact ID_. -Taking Chisel v3.3.2 as an example, the "Artifact ID" is ["chisel3_2.12"](https://search.maven.org/artifact/edu.berkeley.cs/chisel3_2.12) -for Scala 2.12, and ["chisel3_2.11"](https://search.maven.org/artifact/edu.berkeley.cs/chisel3_2.11) for Scala 2.11. - -For more information, see the documentation on the Scala website: -* [Binary Compatibility of Scala Releases](https://docs.scala-lang.org/overviews/core/binary-compatibility-of-scala-releases.html) -* [Binary Compatibility for Library Authoers](https://docs.scala-lang.org/overviews/core/binary-compatibility-for-library-authors.html) - - -### How to Upgrade - -For most users, this is as simple as changing the `scalaVersion` field in your `build.sbt`: -```scala -scalaVersion := "2.11.12" -``` -Becomes -```scala -scalaVersion := "2.12.12" -``` -Now, the next time you run SBT, it will be using the Scala 2.12 version of Chisel 3 (as well as any other dependencies you have). - -### Common Issues - -As mentioned in the [previous section](#scala-versioning), Scala does *not* maintain source compatibilty between major versions. -Put another way, sometimes they break things in backwards incompatible ways. -This section includes some common issues that Chisel users run into and how to fix them. - -For complete information about changes, please see the [release notes for Scala 2.12.0](https://www.scala-lang.org/news/2.12.0/). - -#### Value is not a member of chisel3.Bundle - -The most common problem for Chisel users upgrading from Scala 2.11 to 2.12 is a change in Scala type inference. -This usually occurs in the context of `io` `Bundles` in `Modules`, given: -```scala mdoc:silent -class Foo extends Module { - val io = IO(new Bundle { - val in = Input(Bool()) - val out = Output(Bool()) - }) - - io.out := ~io.in -} -``` -You may see an error that says somethign like "value out is not a member of chisel3.Bundle": -``` -[error] /workspace/src/main/scala/gcd/Foo.scala:9:6: value out is not a member of chisel3.Bundle -[error] io.out := ~io.in -[error] ^ -[error] /workspace/src/main/scala/gcd/Foo.scala:9:17: value in is not a member of chisel3.Bundle -[error] io.out := ~io.in -[error] ^ -[error] two errors found -``` -This can be worked around by adding `-Xsource:2.11` to your `scalacOptions`. -This is most commonly set in your `build.sbt`. -For an example, see the [chisel-template's build.sbt](https://github.com/freechipsproject/chisel-template/blob/11f6ca470120908d167cb8dc3241953eb31d0acb/build.sbt#L10). - - -- cgit v1.2.3 From 73184b7374bf4e7bccd609093c9614a5b95ea690 Mon Sep 17 00:00:00 2001 From: chrisbaldwin2 Date: Tue, 2 Mar 2021 15:12:17 -0500 Subject: Adding ChiselEnum Documentation Entry (#1795) * Adding ChiselEnum Documentation Entry Added documentation for the ChiselEnum type with verified examples * Fixed some doc ambiguity and repeated emitVerilog calls * Added ChiselStage and commented out package definition since packages cannot be declared in single files * Fixed issue with ChiselStage not being able to generate a module with parameters and bad package imports * Opps on not adding _ after import * Update docs/src/explanations/chisel-enum.md Co-authored-by: Megan Wachs * Update docs/src/explanations/chisel-enum.md Co-authored-by: Megan Wachs * Modified Bundle for ci and made changes to select naming scheme * Update docs/src/explanations/chisel-enum.md Co-authored-by: Megan Wachs * Update docs/src/explanations/chisel-enum.md Co-authored-by: Megan Wachs * Update docs/src/explanations/chisel-enum.md Co-authored-by: Megan Wachs * Update docs/src/explanations/chisel-enum.md Co-authored-by: Megan Wachs * Added missing backticks * Added space around error block quote * Fixed md paragraph in code * Update docs/src/explanations/chisel-enum.md Co-authored-by: Megan Wachs * Update docs/src/explanations/chisel-enum.md Co-authored-by: Schuyler Eldridge * Update docs/src/explanations/chisel-enum.md Co-authored-by: Schuyler Eldridge * Update docs/src/explanations/chisel-enum.md Co-authored-by: Schuyler Eldridge * Update docs/src/explanations/chisel-enum.md Co-authored-by: Megan Wachs * Fixed some comments and formatting Co-authored-by: Megan Wachs Co-authored-by: Schuyler Eldridge --- docs/src/explanations/chisel-enum.md | 134 +++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 docs/src/explanations/chisel-enum.md (limited to 'docs') diff --git a/docs/src/explanations/chisel-enum.md b/docs/src/explanations/chisel-enum.md new file mode 100644 index 00000000..c4ee6af6 --- /dev/null +++ b/docs/src/explanations/chisel-enum.md @@ -0,0 +1,134 @@ +# ChiselEnum + +The ChiselEnum type can be used to reduce the chance of error when encoding mux selectors, opcodes, and functional unit operations. In contrast with`Chisel.util.Enum`, `ChiselEnum` are subclasses of `Data`, which means that they can be used to define fields in `Bundle`s, including in `IO`s. + + +## Functionality and Examples + +```scala mdoc +// Imports used in the following examples +import chisel3._ +import chisel3.util._ +import chisel3.stage.ChiselStage +import chisel3.experimental.ChiselEnum +``` + +Below we see ChiselEnum being used as mux select for a RISC-V core. While wrapping the object in a package is not required, it is highly recommended as it allows for the type to be used in multiple files more easily. + +```scala mdoc +// package CPUTypes { + object AluMux1Sel extends ChiselEnum { + val selectRS1, selectPC = Value + /** How the values will be mapped + "selectRS1" -> 0.U, + "selectPC" -> 1.U + */ + } +// } +``` + +Here we see a mux using the AluMux1Sel to select between different inputs. + +```scala mdoc +import AluMux1Sel._ + +class AluMux1Bundle extends Bundle { + val aluMux1Sel = Input( AluMux1Sel() ) + val rs1Out = Input(Bits(32.W)) + val pcOut = Input(Bits(32.W)) + val aluMux1Out = Output(Bits(32.W)) +} + +class AluMux1File extends Module { + val io = IO(new AluMux1Bundle) + + // Default value for aluMux1Out + io.aluMux1Out := 0.U + + switch (io.aluMux1Sel) { + is (selectRS1) { + io.aluMux1Out := io.rs1Out + } + is (selectPC) { + io.aluMux1Out := io.pcOut + } + } +} +``` +```scala mdoc:verilog +ChiselStage.emitVerilog(new AluMux1File ) +``` + +ChiselEnum also allows for the user to define variables by passing in the value shown below. Note that the value must be increasing or else + + > chisel3.internal.ChiselException: Exception thrown when elaborating ChiselGeneratorAnnotation + +is thrown during Verilog generation. + +```scala mdoc +object Opcode extends ChiselEnum { + val load = Value(0x03.U) // i "load" -> 000_0011 + val imm = Value(0x13.U) // i "imm" -> 001_0011 + val auipc = Value(0x17.U) // u "auipc" -> 001_0111 + val store = Value(0x23.U) // s "store" -> 010_0011 + val reg = Value(0x33.U) // r "reg" -> 011_0011 + val lui = Value(0x37.U) // u "lui" -> 011_0111 + val br = Value(0x63.U) // b "br" -> 110_0011 + val jalr = Value(0x67.U) // i "jalr" -> 110_0111 + val jal = Value(0x6F.U) // j "jal" -> 110_1111 +} +``` + +The user can 'jump' to a value and continue incrementing by passing a start point then using a regular Value assignment. + +```scala mdoc +object BranchFunct3 extends ChiselEnum { + val beq, bne = Value + val blt = Value(4.U) + val bge, bltu, bgeu = Value + /** How the values will be mapped + "beq" -> 0.U, + "bne" -> 1.U, + "blt" -> 4.U, + "bge" -> 5.U, + "bltu" -> 6.U, + "bgeu" -> 7.U + */ +} +``` + +## Testing + +When testing your modules, the `.Type` and `.litValue` attributes allow for the the objects to be passed as parameters and for the value to be converted to BigInt type. Note that BigInts cannot be casted to Int with `.asInstanceOf[Int]`, they use their own methods like `toInt`. Please review the [scala.math.BigInt](https://www.scala-lang.org/api/2.12.5/scala/math/BigInt.html) page for more details! + +```scala mdoc +def expectedSel(sel: AluMux1Sel.Type): Boolean = sel match { + case AluMux1Sel.selectRS1 => (sel.litValue == 0) + case AluMux1Sel.selectPC => (sel.litValue == 1) + case _ => false +} +``` + +The ChiselEnum type also has methods `.all` and `.getWidth` where `all` returns all of the enum instances and `getWidth` returns the width of the hardware type. + +## Workarounds + +As of 2/26/2021, the width of the values is always inferred. To work around this, you can add an extra `Value` that forces the width that is desired. This is shown in the example below, where we add a field `ukn` to force the width to be 3 bits wide: + +```scala mdoc +object StoreFunct3 extends ChiselEnum { + val sb, sh, sw = Value + val ukn = Value(7.U) + /** How the values will be mapped + "sb" -> 0.U, + "sh" -> 1.U, + "sw" -> 2.U + */ +} +``` + +Signed values are not supported so if you want the value signed, you must cast the UInt with `.asSInt`. + +## Additional Resources + +The ChiselEnum type is much more powerful than stated above. It allows for Sequence, Vec, and Bundle assignments, as well as a `.next` operation to allow for stepping through sequential states and an `.isValid` for checking that a hardware value is a valid `Value`. The source code for the ChiselEnum can be found [here](https://github.com/chipsalliance/chisel3/blob/2a96767097264eade18ff26e1d8bce192383a190/core/src/main/scala/chisel3/StrongEnum.scala) in the class `EnumFactory`. Examples of the ChiselEnum operations can be found [here](https://github.com/chipsalliance/chisel3/blob/dd6871b8b3f2619178c2a333d9d6083805d99e16/src/test/scala/chiselTests/StrongEnum.scala). -- cgit v1.2.3 From 36e722394cef921967232c63c6e50f5d6bbc0d26 Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Wed, 3 Mar 2021 11:15:31 -0800 Subject: Add header for chisel-enum.md (#1800) --- docs/src/explanations/chisel-enum.md | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'docs') diff --git a/docs/src/explanations/chisel-enum.md b/docs/src/explanations/chisel-enum.md index c4ee6af6..cb017239 100644 --- a/docs/src/explanations/chisel-enum.md +++ b/docs/src/explanations/chisel-enum.md @@ -1,3 +1,9 @@ +--- +layout: docs +title: "Enumerations" +section: "chisel3" +--- + # ChiselEnum The ChiselEnum type can be used to reduce the chance of error when encoding mux selectors, opcodes, and functional unit operations. In contrast with`Chisel.util.Enum`, `ChiselEnum` are subclasses of `Data`, which means that they can be used to define fields in `Bundle`s, including in `IO`s. -- cgit v1.2.3 From f1ad5b58e8a749d558758288d03ce75bf6b8ff9c Mon Sep 17 00:00:00 2001 From: Megan Wachs Date: Thu, 18 Mar 2021 16:47:58 -0700 Subject: Reorganize website docs (#1806) Updates to chisel3 documentation for website: * guard code examples with mdoc and fix errors encountered along the way * move some website content here vs splitting the content across two repos * Bring in the interval-types and loading memories content so that it will be visible from the website * remove all references to the wiki (deprecated) * Remove reference to Wiki from the README * fix tabbing and compile of chisel3-vs-chisel2 section * Appendix: faqs now guarded and compile * FAQs: move to resources section--- docs/README.md | 7 +- docs/src/appendix/appendix.md | 13 + docs/src/appendix/chisel3-vs-chisel2.md | 62 +-- docs/src/appendix/experimental-features.md | 68 ++- docs/src/cookbooks/cookbook.md | 471 +++++++++++++++++++++ docs/src/cookbooks/cookbooks.md | 15 + docs/src/cookbooks/troubleshooting.md | 64 +++ docs/src/developers/developers.md | 12 + docs/src/developers/sbt-subproject.md | 36 ++ docs/src/developers/style.md | 293 +++++++++++++ docs/src/developers/test-coverage.md | 23 + docs/src/explanations/annotations.md | 8 +- docs/src/explanations/bundles-and-vecs.md | 2 +- docs/src/explanations/combinational-circuits.md | 84 ++++ docs/src/explanations/data-types.md | 136 ++++++ docs/src/explanations/explanations.md | 39 ++ docs/src/explanations/functional-abstraction.md | 34 ++ .../src/explanations/functional-module-creation.md | 120 ++++++ .../src/explanations/interfaces-and-connections.md | 149 +++++++ docs/src/explanations/memories.md | 176 ++++++++ docs/src/explanations/modules.md | 138 ++++++ docs/src/explanations/motivation.md | 44 ++ docs/src/explanations/muxes-and-input-selection.md | 62 +++ docs/src/explanations/operators.md | 65 +++ .../polymorphism-and-parameterization.md | 237 +++++++++++ docs/src/explanations/ports.md | 67 +++ docs/src/explanations/printing.md | 137 ++++++ docs/src/explanations/reset.md | 179 ++++++++ docs/src/explanations/sequential-circuits.md | 50 +++ docs/src/explanations/supported-hardware.md | 11 + docs/src/explanations/unconnected-wires.md | 138 ++++++ docs/src/explanations/width-inference.md | 40 ++ docs/src/introduction.md | 41 ++ docs/src/resources/faqs.md | 284 +++++++++++++ docs/src/resources/resources.md | 17 + docs/src/wiki-deprecated/combinational-circuits.md | 81 ---- docs/src/wiki-deprecated/cookbook.md | 470 -------------------- docs/src/wiki-deprecated/data-types.md | 134 ------ docs/src/wiki-deprecated/developers.md | 11 - docs/src/wiki-deprecated/faqs.md | 246 ----------- docs/src/wiki-deprecated/functional-abstraction.md | 29 -- .../wiki-deprecated/functional-module-creation.md | 79 ---- .../wiki-deprecated/interfaces-and-connections.md | 144 ------- docs/src/wiki-deprecated/interval-type.md | 55 --- docs/src/wiki-deprecated/introduction.md | 64 --- docs/src/wiki-deprecated/memories.md | 170 -------- docs/src/wiki-deprecated/modules.md | 135 ------ .../wiki-deprecated/muxes-and-input-selection.md | 56 --- docs/src/wiki-deprecated/operators.md | 63 --- .../polymorphism-and-parameterization.md | 209 --------- docs/src/wiki-deprecated/ports.md | 67 --- docs/src/wiki-deprecated/printing.md | 130 ------ docs/src/wiki-deprecated/reset.md | 177 -------- docs/src/wiki-deprecated/resources.md | 14 - docs/src/wiki-deprecated/sbt-subproject.md | 36 -- docs/src/wiki-deprecated/sequential-circuits.md | 42 -- docs/src/wiki-deprecated/style.md | 275 ------------ docs/src/wiki-deprecated/supported-hardware.md | 8 - docs/src/wiki-deprecated/test-coverage.md | 21 - docs/src/wiki-deprecated/troubleshooting.md | 57 --- docs/src/wiki-deprecated/unconnected-wires.md | 112 ----- docs/src/wiki-deprecated/width-inference.md | 37 -- 62 files changed, 3284 insertions(+), 2960 deletions(-) create mode 100644 docs/src/appendix/appendix.md create mode 100644 docs/src/cookbooks/cookbook.md create mode 100644 docs/src/cookbooks/cookbooks.md create mode 100644 docs/src/cookbooks/troubleshooting.md create mode 100644 docs/src/developers/developers.md create mode 100644 docs/src/developers/sbt-subproject.md create mode 100644 docs/src/developers/style.md create mode 100644 docs/src/developers/test-coverage.md create mode 100644 docs/src/explanations/combinational-circuits.md create mode 100644 docs/src/explanations/data-types.md create mode 100644 docs/src/explanations/explanations.md create mode 100644 docs/src/explanations/functional-abstraction.md create mode 100644 docs/src/explanations/functional-module-creation.md create mode 100644 docs/src/explanations/interfaces-and-connections.md create mode 100644 docs/src/explanations/memories.md create mode 100644 docs/src/explanations/modules.md create mode 100644 docs/src/explanations/motivation.md create mode 100644 docs/src/explanations/muxes-and-input-selection.md create mode 100644 docs/src/explanations/operators.md create mode 100644 docs/src/explanations/polymorphism-and-parameterization.md create mode 100644 docs/src/explanations/ports.md create mode 100644 docs/src/explanations/printing.md create mode 100644 docs/src/explanations/reset.md create mode 100644 docs/src/explanations/sequential-circuits.md create mode 100644 docs/src/explanations/supported-hardware.md create mode 100644 docs/src/explanations/unconnected-wires.md create mode 100644 docs/src/explanations/width-inference.md create mode 100644 docs/src/introduction.md create mode 100644 docs/src/resources/faqs.md create mode 100644 docs/src/resources/resources.md delete mode 100644 docs/src/wiki-deprecated/combinational-circuits.md delete mode 100644 docs/src/wiki-deprecated/cookbook.md delete mode 100644 docs/src/wiki-deprecated/data-types.md delete mode 100644 docs/src/wiki-deprecated/developers.md delete mode 100644 docs/src/wiki-deprecated/faqs.md delete mode 100644 docs/src/wiki-deprecated/functional-abstraction.md delete mode 100644 docs/src/wiki-deprecated/functional-module-creation.md delete mode 100644 docs/src/wiki-deprecated/interfaces-and-connections.md delete mode 100644 docs/src/wiki-deprecated/interval-type.md delete mode 100644 docs/src/wiki-deprecated/introduction.md delete mode 100644 docs/src/wiki-deprecated/memories.md delete mode 100644 docs/src/wiki-deprecated/modules.md delete mode 100644 docs/src/wiki-deprecated/muxes-and-input-selection.md delete mode 100644 docs/src/wiki-deprecated/operators.md delete mode 100644 docs/src/wiki-deprecated/polymorphism-and-parameterization.md delete mode 100644 docs/src/wiki-deprecated/ports.md delete mode 100644 docs/src/wiki-deprecated/printing.md delete mode 100644 docs/src/wiki-deprecated/reset.md delete mode 100644 docs/src/wiki-deprecated/resources.md delete mode 100644 docs/src/wiki-deprecated/sbt-subproject.md delete mode 100644 docs/src/wiki-deprecated/sequential-circuits.md delete mode 100644 docs/src/wiki-deprecated/style.md delete mode 100644 docs/src/wiki-deprecated/supported-hardware.md delete mode 100644 docs/src/wiki-deprecated/test-coverage.md delete mode 100644 docs/src/wiki-deprecated/troubleshooting.md delete mode 100644 docs/src/wiki-deprecated/unconnected-wires.md delete mode 100644 docs/src/wiki-deprecated/width-inference.md (limited to 'docs') diff --git a/docs/README.md b/docs/README.md index dfc7f934..2a34fc45 100644 --- a/docs/README.md +++ b/docs/README.md @@ -8,8 +8,7 @@ as part of the PR CI checks, forcing the documentation to remain current with the codebase. The `src` folder contains the source from which these are generated. -Previous Wiki documentation, now hosted by the website, is contained in the `src/wiki-deprecated` directory. -We are in the process of converting this documentation into the four categories as described in +Our documentation is organized into the four categories as described in [Divio's documentation system](https://documentation.divio.com/). The four documentation types are: @@ -22,9 +21,7 @@ Our documentation strategy for this repository is as follows: * Any new public API requires reference documentation. * Any new user-facing feature requires explanation documentation. * Any bugfixes, corner-cases, or answers to commonly asked questions requires a how-to guide. - * For now, tutorials are kept in a separate repository. We are working hosting them here. - * Old documentation is contained in the `src/wiki-deprecated` directory and is being incrementally converted to these - categories. + * Tutorials are kept in a separate repository. This documentation is hosted on the Chisel [website](https://www.chisel-lang.org). diff --git a/docs/src/appendix/appendix.md b/docs/src/appendix/appendix.md new file mode 100644 index 00000000..48106fe4 --- /dev/null +++ b/docs/src/appendix/appendix.md @@ -0,0 +1,13 @@ +--- +layout: docs +title: "Appendix" +section: "chisel3" +--- + +# Appendix + +This section covers some less-common Chisel topics. + +* [Differences between Chisel3 and Chisel2](chisel3-vs-chisel2) +* [Experimental Features](experimental-features) +* [Upgrading from Scala 2.11](upgrading-from-scala-2-11) diff --git a/docs/src/appendix/chisel3-vs-chisel2.md b/docs/src/appendix/chisel3-vs-chisel2.md index bfd20348..cafd29e3 100644 --- a/docs/src/appendix/chisel3-vs-chisel2.md +++ b/docs/src/appendix/chisel3-vs-chisel2.md @@ -5,6 +5,9 @@ section: "chisel3" --- # Chisel3 vs Chisel2 +```scala mdoc:invisible +import chisel3._ +``` ## Chisel2 Migration For those moving from Chisel2, there were some backwards incompatible changes @@ -12,55 +15,66 @@ and your RTL needs to be modified to work with Chisel3. The required modifications are: - Wire declaration style: - ```scala - val wire = UInt(width = 15) - ``` +```scala + val wire = UInt(width = 15) +``` becomes (in Chisel3): - ```scala - val wire = Wire(UInt(15.W)) - ``` +```scala mdoc:compile-only + val wire = Wire(UInt(15.W)) +``` - I/O declaration style: - ```scala +```scala val done = Bool(OUTPUT) - ``` +``` becomes (in Chisel3): - ```scala +```scala mdoc:compile-only val wire = Output(Bool()) - ``` +``` - Sequential memories: - ```scala +```scala mdoc:invisible +import chisel3._ +val enable = Bool() +``` + +```scala val addr = Reg(UInt()) val mem = Mem(UInt(8.W), 1024, seqRead = true) val dout = when(enable) { mem(addr) } - ``` +``` becomes (in Chisel3): - ```scala +```scala mdoc:compile-only val addr = UInt() val mem = SyncReadMem(1024, UInt(8.W)) val dout = mem.read(addr, enable) - ``` +``` Notice the address register is now internal to the SyncReadMem(), but the data will still return on the subsequent cycle. - - Generating Verilog with - ```scala + - Generating Verilog for a module: +```scala mdoc:invisible +import chisel3._ +class Hello extends RawModule +``` + +```scala object Hello { def main(args: Array[String]): Unit = { chiselMain(Array("--backend", "v"), () => Module(new Hello())) } } - ``` +``` becomes (in Chisel3): - ```scala +```scala mdoc:compile-only + import chisel3.stage.ChiselStage object Hello { def main(args: Array[String]): Unit = { - chisel3.Driver.execute(Array[String](), () => new Hello()) + (new ChiselStage).emitVerilog(new Hello()) } } - ``` +``` - Package changes: - Chisel.log2Ceil -> chisel3.util.log2Ceil @@ -143,14 +157,14 @@ hardware objects), based on specific imports. This allows designs to move from less strict front end checks (largely compatible with Chisel2), to stricter checking, on a file by file basis, by adjusting specific import statements. -```scala - import chisel3.core.ExplicitCompileOptions.Strict +```scala mdoc:compile-only + import chisel3.ExplicitCompileOptions.Strict ``` enables stricter connection and usage checks, while -```scala - import chisel3.core.ExplicitCompileOptions.NotStrict +```scala mdoc:compile-only + import chisel3.ExplicitCompileOptions.NotStrict ``` defers these checks to the `firrtl` compiler. diff --git a/docs/src/appendix/experimental-features.md b/docs/src/appendix/experimental-features.md index ba1a028d..0e3f50c8 100644 --- a/docs/src/appendix/experimental-features.md +++ b/docs/src/appendix/experimental-features.md @@ -6,12 +6,18 @@ section: "chisel3" Chisel has a number of new features that are worth checking out. This page is an informal list of these features and projects. -### FixedPoint +[FixedPoint](#fixed-point) +[Module Variants](#module-variants) +[Module Variants](#bundle-literals) +[Interval Type](#interval-type) +[Loading Memories in Simulation](#loading-memories) + +### FixedPoint FixedPoint numbers are basic *Data* type along side of UInt, SInt, etc. Most common math and logic operations are supported. Chisel allows both the width and binary point to be inferred by the Firrtl compiler which can simplify circuit descriptions. See [FixedPointSpec](https://github.com/freechipsproject/chisel3/tree/master/src/test/scala/chiselTests/FixedPointSpec.scala) -### Module Variants +### Module Variants The standard Chisel *Module* requires a `val io = IO(...)`, the experimental package introduces several new ways of defining Modules - BaseModule: no contents, instantiable @@ -21,7 +27,7 @@ new ways of defining Modules - RawModule: will be the user-facing version of UserDefinedModule - Module: type-aliases to ImplicitModule, the user-facing version of ImplicitModule. -### Bundle Literals +### Bundle Literals Bundle literals can be constructed via an experimental import: @@ -81,7 +87,7 @@ chisel3.stage.ChiselStage.emitVerilog(new Example3) Vec literals are not yet supported. -### Interval Type +### Interval Type **Intervals** are a new experimental numeric type that comprises UInt, SInt and FixedPoint numbers. It augments these types with range information, i.e. upper and lower numeric bounds. @@ -136,3 +142,57 @@ Consider a Interval with a binary point of 3: aaa.bbb | setBinaryPoint(2) | aaa.bb | 2 | X | X | set the precision | | shiftLeftBinaryPoint(2) | a.aabbb | 5 | X | X | increase the precision | | shiftRighBinaryPoint(2) | aaaa.b | 1 | X | X | reduce the precision | + +## Loading Memories in simulation + +Chisel now supports an experimental method for annotating memories to be loaded from a text file containing +hex or binary numbers. When using verilog simulation it uses the `$readmemh` or `$readmemb` +verilog extension. The treadle simulator can also load memories using the same annotation. + +### How to annotate +Assuming you have a memory in a Module +```scala mdoc:invisible +import chisel3._ +val memoryDepth = 8 +val memoryType = Bool() +``` +```scala +val memory = Mem(memoryDepth, memoryType) +``` + +At the top of your file just add the import +```scala mdoc:silent +import chisel3.util.experimental.loadMemoryFromFile +``` +Now just add the memory annotation using +```scala + loadMemoryFromFile(memory, "/workspace/workdir/mem1.txt") +``` +The default is to use `$readmemh` (which assumes all numbers in the file are in ascii hex), +bu to use ascii binary there is an optional third argument. You will need to add an additional import. +```scala mdoc:silent +import firrtl.annotations.MemoryLoadFileType +``` +```scala + loadMemoryFromFile(memory, "/workspace/workdir/mem1.txt", MemoryLoadFileType.Binary) +``` +See: [ComplexMemoryLoadingSpec.scala](https://freechipsproject/chisel-testers/src/test/scala/examples/ComplexMemoryLoadingSpec.scala) and +[LoadMemoryFromFileSpec.scala](https://github.com/freechipsproject/chisel-testers/src/test/scala/examples/LoadMemoryFromFileSpec.scala) +for working examples. + +### Notes on files +There is no simple answer to where to put this file. It's probably best to create a resource directory somewhere and reference that through a full path. Because these files may be large, we did not want to copy them. +> Don't forget there is no decimal option, so a 10 in an input file will be 16 decimal + +### Aggregate memories +Aggregate memories are supported but in bit of a clunky way. Since they will be split up into a memory per field, the following convention was adopted. When specifying the file for such a memory the file name should be regarded as a template. If the memory is a Bundle e.g. +```scala mdoc:compile-only +class MemDataType extends Bundle { + val a = UInt(16.W) + val b = UInt(32.W) + val c = Bool() +} +``` +The memory will be split into `memory_a`, `memory_b`, and `memory_c`. Similarly if a load file is specified as `"memory-load.txt"` the simulation will expect that there will be three files, `"memory-load_a.txt"`, `"memory-load_b.txt"`, `"memory-load_c.txt"` + +> Note: The use of `_` and that the memory field name is added before any file suffix. The suffix is optional but if present is considered to be the text after the last `.` in the file name. diff --git a/docs/src/cookbooks/cookbook.md b/docs/src/cookbooks/cookbook.md new file mode 100644 index 00000000..6a8eeebf --- /dev/null +++ b/docs/src/cookbooks/cookbook.md @@ -0,0 +1,471 @@ +--- +layout: docs +title: "General Cookbook" +section: "chisel3" +--- + +# General Cookbook + + +Please note that these examples make use of [Chisel's scala-style printing](../explanations/printing#scala-style). + +* Converting Chisel Types to/from UInt + * [How do I create a UInt from an instance of a Bundle?](#how-do-i-create-a-uint-from-an-instance-of-a-bundle) + * [How do I create a Bundle from a UInt?](#how-do-i-create-a-bundle-from-a-uint) + * [How do I create a Vec of Bools from a UInt?](#how-do-i-create-a-vec-of-bools-from-a-uint) + * [How do I create a UInt from a Vec of Bool?](#how-do-i-create-a-uint-from-a-vec-of-bool) +* Vectors and Registers + * [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 create a finite state machine?](#how-do-i-create-a-finite-state-machine-fsm) +* [How do I unpack a value ("reverse concatenation") like in Verilog?](#how-do-i-unpack-a-value-reverse-concatenation-like-in-verilog) +* [How do I do subword assignment (assign to some bits in a UInt)?](#how-do-i-do-subword-assignment-assign-to-some-bits-in-a-uint) +* [How do I create an optional I/O?](#how-do-i-create-an-optional-io) +* Predictable Naming + * [How do I get Chisel to name signals properly in blocks like when/withClockAndReset?](#how-do-i-get-chisel-to-name-signals-properly-in-blocks-like-whenwithclockandreset) + * [How do I get Chisel to name the results of vector reads properly?](#how-do-i-get-chisel-to-name-the-results-of-vector-reads-properly) + * [How can I dynamically set/parametrize the name of a module?](#how-can-i-dynamically-setparametrize-the-name-of-a-module) + +## Converting Chisel Types to/from UInt + +### How do I create a UInt from an instance of a Bundle? + +Call [`asUInt`](https://www.chisel-lang.org/api/latest/chisel3/Bundle.html#asUInt():chisel3.UInt) on the [`Bundle`](https://www.chisel-lang.org/api/latest/chisel3/Bundle.html) instance. + +```scala mdoc:silent:reset +import chisel3._ + +class MyBundle extends Bundle { + val foo = UInt(4.W) + val bar = UInt(4.W) +} + +class Foo extends RawModule { + val bundle = Wire(new MyBundle) + bundle.foo := 0xc.U + bundle.bar := 0x3.U + val uint = bundle.asUInt +} +``` + +### How do I create a Bundle from a UInt? + +Use the [`asTypeOf`](https://www.chisel-lang.org/api/latest/chisel3/UInt.html#asTypeOf[T%3C:chisel3.Data](that:T):T) method to reinterpret the [`UInt`](https://www.chisel-lang.org/api/latest/chisel3/UInt.html) as the type of the [`Bundle`](https://www.chisel-lang.org/api/latest/chisel3/Bundle.html). + +```scala mdoc:silent:reset +import chisel3._ + +class MyBundle extends Bundle { + val foo = UInt(4.W) + val bar = UInt(4.W) +} + +class Foo extends RawModule { + val uint = 0xb4.U + val bundle = uint.asTypeOf(new MyBundle) +} +``` + +### How do I create a Vec of Bools from a UInt? + +Use [`VecInit`](https://www.chisel-lang.org/api/latest/chisel3/VecInit$.html) given a `Seq[Bool]` generated using the [`asBools`](https://www.chisel-lang.org/api/latest/chisel3/UInt.html#asBools():Seq[chisel3.Bool]) method. + +```scala mdoc:silent:reset +import chisel3._ + +class Foo extends RawModule { + val uint = 0xc.U + val vec = VecInit(uint.asBools) +} +``` + +### How do I create a UInt from a Vec of Bool? + +Use the builtin function [`asUInt`](https://www.chisel-lang.org/api/latest/chisel3/Vec.html#asUInt():chisel3.UInt) + +```scala mdoc:silent:reset +import chisel3._ + +class Foo extends RawModule { + val vec = VecInit(true.B, false.B, true.B, true.B) + val uint = vec.asUInt +} +``` + +## Vectors and Registers + +### How do I create a Vector of Registers? + +**Rule! Use Reg of Vec not Vec of Reg!** + +You create a [Reg of type Vec](#how-do-i-create-a-reg-of-type-vec). Because Vecs are a *type* (like `UInt`, `Bool`) rather than a *value*, we must bind the Vec to some concrete *value*. + +### How do I create a Reg of type Vec? + +For more information, the API Documentation for [`Vec`](https://www.chisel-lang.org/api/latest/chisel3/Vec.html) provides more information. + +```scala mdoc:silent:reset +import chisel3._ + +class Foo extends RawModule { + val regOfVec = Reg(Vec(4, UInt(32.W))) // Register of 32-bit UInts + regOfVec(0) := 123.U // Assignments to elements of the Vec + regOfVec(1) := 456.U + regOfVec(2) := 789.U + regOfVec(3) := regOfVec(0) + + // Reg of Vec of 32-bit UInts initialized to zero + // Note that Seq.fill constructs 4 32-bit UInt literals with the value 0 + // VecInit(...) then constructs a Wire of these literals + // The Reg is then initialized to the value of the Wire (which gives it the same type) + val initRegOfVec = RegInit(VecInit(Seq.fill(4)(0.U(32.W)))) +} +``` + +### How do I create a finite state machine (FSM)? + +The advised way is to use [`ChiselEnum`](https://www.chisel-lang.org/api/latest/chisel3/experimental/index.html#ChiselEnum=chisel3.experimental.EnumFactory) to construct enumerated types representing the state of the FSM. +State transitions are then handled with [`switch`](https://www.chisel-lang.org/api/latest/chisel3/util/switch$.html)/[`is`](https://www.chisel-lang.org/api/latest/chisel3/util/is$.html) and [`when`](https://www.chisel-lang.org/api/latest/chisel3/when$.html)/[`.elsewhen`](https://www.chisel-lang.org/api/latest/chisel3/WhenContext.html#elsewhen(elseCond:=%3Echisel3.Bool)(block:=%3EUnit)(implicitsourceInfo:chisel3.internal.sourceinfo.SourceInfo,implicitcompileOptions:chisel3.CompileOptions):chisel3.WhenContext)/[`.otherwise`](https://www.chisel-lang.org/api/latest/chisel3/WhenContext.html#otherwise(block:=%3EUnit)(implicitsourceInfo:chisel3.internal.sourceinfo.SourceInfo,implicitcompileOptions:chisel3.CompileOptions):Unit). + +```scala mdoc:silent:reset +import chisel3._ +import chisel3.util.{switch, is} +import chisel3.experimental.ChiselEnum + +object DetectTwoOnes { + object State extends ChiselEnum { + val sNone, sOne1, sTwo1s = Value + } +} + +/* This FSM detects two 1's one after the other */ +class DetectTwoOnes extends Module { + import DetectTwoOnes.State + import DetectTwoOnes.State._ + + val io = IO(new Bundle { + val in = Input(Bool()) + val out = Output(Bool()) + val state = Output(State()) + }) + + val state = RegInit(sNone) + + io.out := (state === sTwo1s) + io.state := state + + switch (state) { + is (sNone) { + when (io.in) { + state := sOne1 + } + } + is (sOne1) { + when (io.in) { + state := sTwo1s + } .otherwise { + state := sNone + } + } + is (sTwo1s) { + when (!io.in) { + state := sNone + } + } + } +} +``` + +Note: the `is` statement can take multiple conditions e.g. `is (sTwo1s, sOne1) { ... }`. + +### How do I unpack a value ("reverse concatenation") like in Verilog? + +In Verilog, you can do something like the following which will unpack a the value `z`: + +```verilog +wire [1:0] a; +wire [3:0] b; +wire [2:0] c; +wire [8:0] z = [...]; +assign {a,b,c} = z; +``` + +Unpacking often corresponds to reinterpreting an unstructured data type as a structured data type. +Frequently, this structured type is used prolifically in the design, and has been declared as in the following example: + +```scala mdoc:silent:reset +import chisel3._ + +class MyBundle extends Bundle { + val a = UInt(2.W) + val b = UInt(4.W) + val c = UInt(3.W) +} +``` + +The easiest way to accomplish this in Chisel would be: + +```scala mdoc:silent +class Foo extends RawModule { + val z = Wire(UInt(9.W)) + z := DontCare // This is a dummy connection + val unpacked = z.asTypeOf(new MyBundle) + printf("%d", unpacked.a) + printf("%d", unpacked.b) + printf("%d", unpacked.c) +} +``` + +If you **really** need to do this for a one-off case (Think thrice! It is likely you can better structure the code using bundles), then rocket-chip has a [Split utility](https://github.com/freechipsproject/rocket-chip/blob/723af5e6b69e07b5f94c46269a208a8d65e9d73b/src/main/scala/util/Misc.scala#L140) which can accomplish this. + +### How do I do subword assignment (assign to some bits in a UInt)? + +You may try to do something like the following where you want to assign only some bits of a Chisel type. +Below, the left-hand side connection to `io.out(0)` is not allowed. + +```scala mdoc:silent:reset +import chisel3._ +import chisel3.stage.{ChiselStage, ChiselGeneratorAnnotation} + +class Foo extends Module { + val io = IO(new Bundle { + val bit = Input(Bool()) + val out = Output(UInt(10.W)) + }) + io.out(0) := io.bit +} +``` + +If you try to compile this, you will get an error. +```scala mdoc:crash +(new ChiselStage).execute(Array("-X", "verilog"), Seq(new ChiselGeneratorAnnotation(() => new Foo))) +``` + +Chisel3 *does not support subword assignment*. +The reason for this is that subword assignment generally hints at a better abstraction with an aggregate/structured types, i.e., a `Bundle` or a `Vec`. + +If you must express it this way, one approach is to blast your `UInt` to a `Vec` of `Bool` and back: + +```scala mdoc:silent:reset +import chisel3._ + +class Foo extends Module { + val io = IO(new Bundle { + val in = Input(UInt(10.W)) + val bit = Input(Bool()) + val out = Output(UInt(10.W)) + }) + val bools = VecInit(io.in.asBools) + bools(0) := io.bit + io.out := bools.asUInt +} +``` + + +### How do I create an optional I/O? + +The following example is a module which includes the optional port `out2` only if the given parameter is `true`. + +```scala mdoc:silent:reset +import chisel3._ + +class ModuleWithOptionalIOs(flag: Boolean) extends Module { + val io = IO(new Bundle { + val in = Input(UInt(12.W)) + val out = Output(UInt(12.W)) + val out2 = if (flag) Some(Output(UInt(12.W))) else None + }) + + io.out := io.in + if (flag) { + io.out2.get := io.in + } +} +``` + +The following is an example where an entire `IO` is optional: + +```scala mdoc:silent:reset +import chisel3._ + +class ModuleWithOptionalIO(flag: Boolean) extends Module { + val in = if (flag) Some(IO(Input(Bool()))) else None + val out = IO(Output(Bool())) + + out := in.getOrElse(false.B) +} +``` + +## Predictable Naming + +### How do I get Chisel to name signals properly in blocks like when/withClockAndReset? + +To get Chisel to name signals (wires and registers) declared inside of blocks like `when`, `withClockAndReset`, etc, use the [`@chiselName`](https://www.chisel-lang.org/api/latest/chisel3/experimental/package$$chiselName.html) annotation as shown below: + +```scala mdoc:silent:reset +import chisel3._ +import chisel3.experimental.chiselName + +@chiselName +class TestMod extends Module { + val io = IO(new Bundle { + val a = Input(Bool()) + val b = Output(UInt(4.W)) + }) + when (io.a) { + val innerReg = RegInit(5.U(4.W)) + innerReg := innerReg + 1.U + io.b := innerReg + } .otherwise { + io.b := 10.U + } +} +``` + +Note that you will need to add the following line to your project's `build.sbt` file. + +```scala +addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full) +``` + +If we compile this module *without* `@chiselName`, Chisel is not able to name `innerReg` correctly (notice the `_T`): + +```scala mdoc:passthrough +import chisel3.stage.{ChiselStage, ChiselGeneratorAnnotation} +import firrtl.annotations.DeletedAnnotation +import firrtl.EmittedVerilogCircuitAnnotation + +class TestModWithout extends Module { + override val desiredName = "TestMod" + val io = IO(new Bundle { + val a = Input(Bool()) + val b = Output(UInt(4.W)) + }) + when (io.a) { + val innerReg = RegInit(5.U(4.W)) + innerReg := innerReg + 1.U + io.b := innerReg + } .otherwise { + io.b := 10.U + } +} + +(new ChiselStage) + .execute(Array("-X", "verilog"), Seq(ChiselGeneratorAnnotation(() => new TestModWithout))) + .collectFirst{ case DeletedAnnotation(_, a: EmittedVerilogCircuitAnnotation) => a.value.value } + .foreach(a => println(s"""|```verilog + |$a + |```""".stripMargin)) +``` + +However, if we use `@chiselName` then the register previously called `_T` is now `innerReg`: +```scala mdoc:passthrough +(new ChiselStage) + .execute(Array("-X", "verilog"), Seq(ChiselGeneratorAnnotation(() => new TestMod))) + .collectFirst{ case DeletedAnnotation(_, a: EmittedVerilogCircuitAnnotation) => a.value.value } + .foreach(a => println(s"""|```verilog + |$a + |```""".stripMargin)) +``` +### How do I get Chisel to name the results of vector reads properly? +Currently, name information is lost when using dynamic indexing. For example: +```scala mdoc:silent +class Foo extends Module { + val io = IO(new Bundle { + val in = Input(Vec(4, Bool())) + val idx = Input(UInt(2.W)) + val en = Input(Bool()) + val out = Output(Bool()) + }) + + val x = io.in(io.idx) + val y = x && io.en + io.out := y +} +``` + +The above code loses the `x` name, instead using `_GEN_3` (the other `_GEN_*` signals are expected). +```verilog +module Foo( + input clock, + input reset, + input io_in_0, + input io_in_1, + input io_in_2, + input io_in_3, + input [1:0] io_idx, + input io_en, + output io_out +); + wire _GEN_1; // @[main.scala 15:13] + wire _GEN_2; // @[main.scala 15:13] + wire _GEN_3; // @[main.scala 15:13] + assign _GEN_1 = 2'h1 == io_idx ? io_in_1 : io_in_0; // @[main.scala 15:13] + assign _GEN_2 = 2'h2 == io_idx ? io_in_2 : _GEN_1; // @[main.scala 15:13] + assign _GEN_3 = 2'h3 == io_idx ? io_in_3 : _GEN_2; // @[main.scala 15:13] + assign io_out = _GEN_3 & io_en; // @[main.scala 16:10] +endmodule +``` + +This can be worked around by creating a wire and connecting the dynamic index to the wire: +```scala +val x = WireInit(io.in(io.idx)) +``` + +Which produces: +```verilog +module Foo( + input clock, + input reset, + input io_in_0, + input io_in_1, + input io_in_2, + input io_in_3, + input [1:0] io_idx, + input io_en, + output io_out +); + wire _GEN_1; + wire _GEN_2; + wire x; + assign _GEN_1 = 2'h1 == io_idx ? io_in_1 : io_in_0; + assign _GEN_2 = 2'h2 == io_idx ? io_in_2 : _GEN_1; + assign x = 2'h3 == io_idx ? io_in_3 : _GEN_2; + assign io_out = x & io_en; // @[main.scala 16:10] +endmodule +``` +### How can I dynamically set/parametrize the name of a module? + +You can override the `desiredName` function. This works with normal Chisel modules and `BlackBox`es. Example: + +```scala mdoc:silent:reset +import chisel3._ + +class Coffee extends BlackBox { + val io = IO(new Bundle { + val I = Input(UInt(32.W)) + val O = Output(UInt(32.W)) + }) + override def desiredName = "Tea" +} + +class Salt extends Module { + val io = IO(new Bundle {}) + val drink = Module(new Coffee) + override def desiredName = "SodiumMonochloride" +} +``` + +Elaborating the Chisel module `Salt` yields our "desire name" for `Salt` and `Coffee` in the output Verilog: +```scala mdoc:passthrough +import chisel3.stage.{ChiselStage, ChiselGeneratorAnnotation} +import firrtl.annotations.DeletedAnnotation +import firrtl.EmittedVerilogCircuitAnnotation + +(new ChiselStage) + .execute(Array("-X", "verilog"), Seq(ChiselGeneratorAnnotation(() => new Salt))) + .collectFirst{ case DeletedAnnotation(_, a: EmittedVerilogCircuitAnnotation) => a.value.value } + .foreach(a => println(s"""|```verilog + |$a + |```""".stripMargin)) +``` diff --git a/docs/src/cookbooks/cookbooks.md b/docs/src/cookbooks/cookbooks.md new file mode 100644 index 00000000..ee6f5e45 --- /dev/null +++ b/docs/src/cookbooks/cookbooks.md @@ -0,0 +1,15 @@ +--- +layout: docs +title: "Cookbooks" +section: "chisel3" +--- + +# Cookbooks + +Welcome to the Chisel Cookbooks, where we capture frequently-used design patterns or troubleshooting questions. +If you have any requests or examples to share, +please [file an issue](https://github.com/chipsalliance/chisel3/issues/new) and let us know! + +* [General Cookbooks](cookbook) +* [Naming Cookbook](naming) +* [Troubleshooting Guide](troubleshooting) diff --git a/docs/src/cookbooks/troubleshooting.md b/docs/src/cookbooks/troubleshooting.md new file mode 100644 index 00000000..f8a0cec1 --- /dev/null +++ b/docs/src/cookbooks/troubleshooting.md @@ -0,0 +1,64 @@ +--- +layout: docs +title: "Troubleshooting" +section: "chisel3" +--- + +# Troubleshooting + + +This page is a starting point for recording common and not so common problems in developing with Chisel3. In particular, those situations where there is a work around that will keep you going. + +### `type mismatch` specifying width/value of a `UInt`/`SInt` + +*I have some old code that used to work correctly in chisel2 (and still does if I use the `import Chisel._` compatibility layer) +but causes a `type mismatch` error in straight chisel3:* + +```scala mdoc:silent:fail +class TestBlock extends Module { + val io = IO(new Bundle { + val output = Output(UInt(width=3)) + }) +} +``` +*produces* +```bash +type mismatch; +[error] found : Int(3) +[error] required: chisel3.internal.firrtl.Width +[error] val output = Output(UInt(width=3)) +``` + +The single argument, multi-function object/constructors from chisel2 have been removed from chisel3. +It was felt these were too prone to error and made it difficult to diagnose error conditions in chisel3 code. + +In chisel3, the single argument to the `UInt`/`SInt` object/constructor specifies the *width* and must be a `Width` type. +Although there are no automatic conversions from `Int` to `Width`, an `Int` may be converted to a `Width` by applying the `W` method to an `Int`. +In chisel3, the above code becomes: +```scala mdoc:silent +import chisel3._ + +class TestBlock extends Module { + val io = IO(new Bundle { + val output = Output(UInt(3.W)) + }) +} +``` +`UInt`/`SInt` literals may be created from an `Int` with the application of either the `U` or `S` method. + +```scala mdoc:fail +UInt(42) +``` + +in chisel2, becomes +```scala mdoc:silent +42.U +``` +in chisel3 + +A literal with a specific width is created by calling the `U` or `S` method with a `W` argument. +Use: +```scala mdoc:silent +1.S(8.W) +``` +to create an 8-bit wide (signed) literal with value 1. diff --git a/docs/src/developers/developers.md b/docs/src/developers/developers.md new file mode 100644 index 00000000..b2b5dff8 --- /dev/null +++ b/docs/src/developers/developers.md @@ -0,0 +1,12 @@ +--- +layout: docs +title: "Developers" +section: "chisel3" +--- + +# Developer Documentation + +Tips and tricks for Chisel developers: + +* [Embedding Chisel as an sbt subproject](sbt-subproject) +* [Test Coverage](test-coverage) diff --git a/docs/src/developers/sbt-subproject.md b/docs/src/developers/sbt-subproject.md new file mode 100644 index 00000000..44d2916b --- /dev/null +++ b/docs/src/developers/sbt-subproject.md @@ -0,0 +1,36 @@ +--- +layout: docs +title: "Developers" +section: "chisel3" +--- + +# Chisel as an sbt subproject + +In order to use the constructs defined in the Chisel3 library, those definitions must be made available to the Scala +compiler at the time a project dependent on them is compiled. +For sbt-based builds there are fundamentally two ways to do this: +* provide a library dependency on the published Chisel3 jars via sbt's `libraryDependencies` setting, +* clone the Chisel3 git repository and include the source code as a subproject of a dependent project. + +The former of these two approaches is used by the chisel-tutorial project. +It is the simplest approach and assumes you do not require tight control over Chisel3 source code and are content with the +published release versions of Chisel3. + +The latter approach should be used by Chisel3 projects that require finer control over Chisel3 source code. + +It's hard to predict in advance the future requirements of a project, and it would be advantageous to be able to +switch between the two approaches relatively easily. +In order to accomplish this, we provide the `sbt-chisel-dep` plugin that allows the developer to concisely specify +Chisel3 subproject dependencies and switch between subproject and library dependency support based on the presence of +a directory (or symbolic link) in the root of the dependent project. + +The chisel-template project uses this plugin to support switching between either dependency (subproject or library). +By default, the chisel-template project does not contain a chisel3 subproject directory, and hence, uses a library dependency +on chisel3 (and related Chisel3 projects). +However, if you clone the chisel3 GitHub project from the root directory of the chisel-template project, creating a chisel3 +subdirectory, the `sbt-chisel-dep` plugin will take note of the chisel3 project subdirectory, +and provide an sbt subproject dependency in place of the library dependency. + +Checkout the [README for the `sbt-chisel-dep`](https://github.com/ucb-bar/sbt-chisel-dep) project for instructions on its usage. + +Example versions of the build.sbt and specification of the sbt-chisel-dep plugin are available from the [skeleton branch of the chisel-template repository](https://github.com/ucb-bar/chisel-template/tree/skeleton). diff --git a/docs/src/developers/style.md b/docs/src/developers/style.md new file mode 100644 index 00000000..80e1e083 --- /dev/null +++ b/docs/src/developers/style.md @@ -0,0 +1,293 @@ +--- +layout: docs +title: "Style Guide" +section: "chisel3" +--- + +# Chisel Developers Style Guide + +This document describes the syle used within the `chisel3` +and related projects (`firrtl`, `treadle`, etc). It does not +capture requirements for code which is written using these libraries, +although projects may choose to adopt these guidelines. + +The Chisel style guide reflects the [Google Java style +guide](http://google.github.io/styleguide/javaguide.html) and the [General Public Scala style +guide](http://docs.scala-lang.org/style/). The specific rules below are to clarify +the style used for the chisel3 repo and repos related to Chisel (Firrtl). + + +**Goal:** Readability and consistency are the main purposes of the style guide. +Writing your code so someone else (or yourself) can grok it later is important +to code health and quality. + +## Filenames +The source file name consists of the case-sensitive name of the top-level class +it contains, plus ".scala". + +## Packages + +Package definitions must contain the full path to the package from scala. If +you create a subpackage, it should go in a subdirectory. + + package directory.name.to.get.you.to.your.source + +As in Scala, packages follow the [Java package naming convention](https://google.github.io/styleguide/javaguide.html#s5.2.1-package-names). +Note that these guidelines call for all lowercase, no underscores. + +```scala +// Do this +package hardware.chips.topsecret.masterplan + +// Not this +package hardware.chips.veryObvious.bad_style +``` + +We also suggest you do not use chisel3 as a package, and especially do not use it +as the final (innermost) package. + +```scala +// Don't do this +package hardware.chips.newchip.superfastcomponent.chisel3 + +// This will lead to instantiating package members like so: +val module = Module(new chisel3.FastModule) + +// Which collides with the chisel namespace +import chisel3._ +``` + +## Imports +Avoid wildcard ( ._ ) imports, with the exception of chisel3._ +All other imports must call out used methods. +`import chisel3._` must be first, and separated from remaining imports with an extra blank line. + +**Reason:** This makes it clear where methods are defined. + +Any remaining imports must be listed alphabetically. + +```scala +import chisel3._ + +import the.other.thing.that.i.reference.inline +import the.other.things.that.i.reference.{ClassOne, ClassTwo} + + +val myInline = inline.MakeAnInline() +val myClassOne = new ClassOne +``` + +## Tests +Test classes are named starting with the name of the class they are testing, and +ending with "Test". +Test files must start with the name of the class you are testing and end with +"Test.scala". +Test files should reside in a subdirectory called "tests". +The tests package should be composed of the package class you are testing. + +```scala +package class.under.test.class +package tests +``` + +## Comments +We use scaladoc to automatically generate documentation from the source code. + +```scala +/** Multiple lines of ScalaDoc text are written here, + * wrapped normally... + */ +public int method(String p1) { ... } +``` + +... or in this single-line example: + +```scala +/** An especially short bit of Javadoc. */ +``` + +Write documentation as if the person reading it knows more about Scala and +Chisel than you. If you find comments in the code consider breaking them up +into seperate methods. + +## Module Classes and Instances + +Modules can take different forms in Chisel. The first form is similar to Verilog, where +you instance the module and then hook it up. In this case `Module(new MyMod())` is +returning a reference to the module. + +```scala +val myMod = Module(new MyMod()) +myMod.io <> hookUp +``` + +The second form is a more programmatic inline style with factory methods. In this case, +Queue is actually returning the part of the IO bundle representing the queue's +output. The factory method takes the input IO to the queue and an optional parameter +for depth. + +```scala +val queueOut = Queue(queueIn, depth=10) +``` + +The latter can be used for composing multiple functions into a single line. + +```scala +val queueOut = Queue( + Arbitrate.byRoundRobin( + Queue(a), // depth assumed to be 1 + Queue(b, depth=3), + Queue(c, depth=4) + ), + depth=10 +) +``` + +## Naming Conventions + +Chisel follows the [Scala Naming Conventions](http://docs.scala-lang.org/style/naming-conventions.html). +In general, Chisel code should use `lowerCamelCase` for variable naming (ie. the first letter +of each word is capitalized except for the first word) and `UpperCamelCase` for class names. + +> Using these guidelines can result in verilog which is noncompliant with common verilog coding standards, e.g. +the [lowRISC verilog coding style](https://github.com/lowRISC/style-guides/blob/master/VerilogCodingStyle.md#naming). +Authors of Chisel code that translates to hardware constructs might therefore prefer to use `snake_case`. However, +generated code can always be transformed to meet various emitted code requirements, so the official Chisel style +guide follows the Scala convention. + +### Why CamelCase instead of Snake\_Case? + +The compiler inserts underscores when splitting Chisel/FIRRTL aggregate types +into Verilog types. The compiler uses underscores to preserve the original +structure of the data in the resulting Verilog. Because of the special meaning +of underscores in Chisel-generated Verilog, their use in naming is **strongly** +discouraged. + +Consider the following Chisel code: + +```scala +val msg = Wire(new Bundle { + val valid = Bool() + val addr = UInt(32) + val data = UInt(64) +}) +val msg_rec = Wire(Bool()) +``` + +Which compiles to the Verilog: + +```verilog +wire msg_valid; +wire [31:0] msg_addr; +wire [63:0] msg_data; +wire msg_rec; +``` + +The Verilog maintains the structure of the original aggregate wire `msg`. +However, because we named another variable `msg_rec`, it appears in the Verilog +as if `msg` had 4 fields instead of its actual 3! If we instead follow the +lowerCamelCase for values naming convention, the resulting Verilog makes more +sense: + +```scala +val msg = Wire(new Bundle { + val valid = Bool() + val addr = UInt(32) + val data = UInt(64) +}) +val msgRec = Wire(Bool()) +``` + +And its resulting Verilog: + +```verilog +wire msg_valid; +wire [31:0] msg_addr; +wire [63:0] msg_data; +wire msgRec; +``` + +Much better. + +### Modules and Bundles (Classes, Traits, and Objects) + +Modules are Scala classes and thus use UpperCamelCase. + +```scala +class ModuleNamingExample extends Module { + ... +} +``` + +Similarly, other classes (Chisel & Scala) should be UpperCamelCase as well. + +```scala +trait UsefulScalaUtilities { + def isEven(n: Int): Boolean = (n % 2) == 0 + def isOdd(n: Int): Boolean = !isEven(n) +} + +class MyCustomBundle extends Bundle { + ... +} +// Companion object to MyCustomBundle +object MyCustomBundle { + ... +} + +``` + +### Values and Methods + +Values and methods should use lowerCamelCase. (Unless the value is a constant.) + +```scala +val mySuperReg = Reg(init = 0.asUInt(32)) +def myImportantMethod(a: UInt): Bool = a < 23.asUInt +``` + +### Constants + +Unlike the Google Java style, constants use UpperCamelCase, which is in line +with the official [Scala Naming +Conventions](https://docs.scala-lang.org/style/naming-conventions.html). +Constants are final fields (val or object) whose contents are deeply immutable +and belong to a package object or an object. Examples: + +```scala +// Constants +object Constants { + val Number = 5 + val Names = "Ed" :: "Ann" :: Nil + val Ages = Map("Ed" -> 35, "Ann" -> 32) +} + +// Not constants +class NonConstantsInClass { + val inClass: String = "in-class" +} + +object nonConstantsInObject { + var varString = "var-string" + val mutableCollection: scala.collection.mutable.Set[String] + val mutableElements = Set(mutable) +} +``` + +### UpperCamelCase vs. lowerCamelCase + +There is more than one reasonable way to covert English prose into camel case. +We follow the convention defined in the [Google Java style +guide](https://google.github.io/styleguide/javaguide.html#s5.3-camel-case). The +potentially non-obvious rule being to treat acronymns as words for the purpose +of camel case. + +Note that the casing of the original words is almost entirely disregarded. +Example: + +Prose form | UpperCamelCase | lowerCamelCase | Incorrect +:------------- | :------------- | :------------- | :------------ +find GCD | FindGcd | findGcd | ~~findGCD~~ +state for FSM | StateForFsm | stateForFsm | ~~stateForFSM~~ +mock dut | MockDut | mockDut | ~~MockDUT~~ +FIFO Generator | FifoGenerator | fifoGenerator | ~~FIFOGenerator~~ diff --git a/docs/src/developers/test-coverage.md b/docs/src/developers/test-coverage.md new file mode 100644 index 00000000..099db4bb --- /dev/null +++ b/docs/src/developers/test-coverage.md @@ -0,0 +1,23 @@ +--- +layout: docs +title: "Test Coverage" +section: "chisel3" +--- + +# Test Coverage + +## Test Coverage Setup + +Chisel's sbt build instructions contain the requisite plug-in (sbt-scoverage) for generating test coverage information. Please see the [sbt-scoverage web page](https://github.com/scoverage/sbt-scoverage) for details on the plug-in. +The tests themselves are found in `src/test/scala`. + +## Generating A Test Coverage Report + +Use the following sequence of sbt commands to generate a test coverage report: +``` +sbt clean coverage test +sbt coverageReport +``` +The coverage reports should be found in `target/scala-x.yy/scoverage-report/{scoverage.xml,index.html}` where `x.yy` corresponds to the version of Scala used to compile Firrtl and the tests. +`scoverage.xml` is useful if you want to analyze the results programmatically. +`index.html` is designed for navigation with a web browser, allowing one to drill down to invidual statements covered (or not) by the tests. diff --git a/docs/src/explanations/annotations.md b/docs/src/explanations/annotations.md index 19d24605..510ebca5 100644 --- a/docs/src/explanations/annotations.md +++ b/docs/src/explanations/annotations.md @@ -4,6 +4,8 @@ title: "Annotations" section: "chisel3" --- +# Annotations + `Annotation`s are metadata containers associated with zero or more "things" in a FIRRTL circuit. Commonly, `Annotation`s are used to communicate information from Chisel to a specific, custom FIRRTL `Transform`. In this way `Annotation`s can be viewed as the "arguments" that a specific `Transform` consumes. @@ -132,10 +134,8 @@ class ModC(widthC: Int) extends Module { Compiling this circuit to Verilog will then result in the `InfoTransform` running and the added `println`s showing information about the components annotated. -```scala mdoc +```scala mdoc:compile-only import chisel3.stage.{ChiselStage, ChiselGeneratorAnnotation} -// This currently doesn't work because of mdoc limitations. However, it will work -// in your normal Scala code. -//(new ChiselStage).execute(Array.empty, Seq(ChiselGeneratorAnnotation(() => new ModC(4)))) +(new ChiselStage).execute(Array.empty, Seq(ChiselGeneratorAnnotation(() => new ModC(4)))) ``` diff --git a/docs/src/explanations/bundles-and-vecs.md b/docs/src/explanations/bundles-and-vecs.md index bac9393a..78626c42 100644 --- a/docs/src/explanations/bundles-and-vecs.md +++ b/docs/src/explanations/bundles-and-vecs.md @@ -64,7 +64,7 @@ Note that the builtin Chisel primitive and aggregate classes do not require the `new` when creating an instance, whereas new user datatypes will. A Scala `apply` constructor can be defined so that a user datatype also does not require `new`, as described in -[Function Constructor](../wiki-deprecated/functional-module-creation). +[Function Constructor](../explanations/functional-module-creation). ### Flipping Bundles diff --git a/docs/src/explanations/combinational-circuits.md b/docs/src/explanations/combinational-circuits.md new file mode 100644 index 00000000..b9e5b8c6 --- /dev/null +++ b/docs/src/explanations/combinational-circuits.md @@ -0,0 +1,84 @@ +--- +layout: docs +title: "Combinational Circuits" +section: "chisel3" +--- + +# Combinational Circuits + +A circuit is represented as a graph of nodes in Chisel. Each node is +a hardware operator that has zero or more inputs and that drives one +output. A literal, introduced above, is a degenerate kind of node +that has no inputs and drives a constant value on its output. One way +to create and wire together nodes is using textual expressions. For +example, we can express a simple combinational logic circuit +using the following expression: + +```scala +(a & b) | (~c & d) +``` + +The syntax should look familiar, with `&` and `|` +representing bitwise-AND and -OR respectively, and `~` +representing bitwise-NOT. The names `a` through `d` +represent named wires of some (unspecified) width. + +Any simple expression can be converted directly into a circuit tree, +with named wires at the leaves and operators forming the internal +nodes. The final circuit output of the expression is taken from the +operator at the root of the tree, in this example, the bitwise-OR. + +Simple expressions can build circuits in the shape of trees, but to +construct circuits in the shape of arbitrary directed acyclic graphs +(DAGs), we need to describe fan-out. In Chisel, we do this by naming +a wire that holds a subexpression that we can then reference multiple +times in subsequent expressions. We name a wire in Chisel by +declaring a variable. For example, consider the select expression, +which is used twice in the following multiplexer description: +```scala +val sel = a | b +val out = (sel & in1) | (~sel & in0) +``` + +The keyword `val` is part of Scala, and is used to name variables +that have values that won't change. It is used here to name the +Chisel wire, `sel`, holding the output of the first bitwise-OR +operator so that the output can be used multiple times in the second +expression. + +### Wires + +Chisel also supports wires as hardware nodes to which one can assign values or connect other nodes. + +```scala +val myNode = Wire(UInt(8.W)) +when (isReady) { + myNode := 255.U +} .otherwise { + myNode := 0.U +} +``` + +```scala +val myNode = Wire(UInt(8.W)) +when (input > 128.U) { + myNode := 255.U +} .elsewhen (input > 64.U) { + myNode := 1.U +} .otherwise { + myNode := 0.U +} +``` + +Note that the last connection to a Wire takes effect. For example, the following two Chisel circuits are equivalent: + +```scala +val myNode = Wire(UInt(8.W)) +myNode := 10.U +myNode := 0.U +``` + +```scala +val myNode = Wire(UInt(8.W)) +myNode := 0.U +``` diff --git a/docs/src/explanations/data-types.md b/docs/src/explanations/data-types.md new file mode 100644 index 00000000..6ac6077b --- /dev/null +++ b/docs/src/explanations/data-types.md @@ -0,0 +1,136 @@ +--- +layout: docs +title: "Data Types" +section: "chisel3" +--- + +# Chisel Data Types + +Chisel datatypes are used to specify the type of values held in state +elements or flowing on wires. While hardware designs ultimately +operate on vectors of binary digits, other more abstract +representations for values allow clearer specifications and help the +tools generate more optimal circuits. In Chisel, a raw collection of +bits is represented by the ```Bits``` type. Signed and unsigned integers +are considered subsets of fixed-point numbers and are represented by +types ```SInt``` and ```UInt``` respectively. Signed fixed-point +numbers, including integers, are represented using two's-complement +format. Boolean values are represented as type ```Bool```. Note +that these types are distinct from Scala's builtin types such as +```Int``` or ```Boolean```. + +> There is a new experimental type **Interval** which gives the developer more control of the type by allowing the definition of an IntervalRange. See: [Interval Type](../appendix/experimental-features#interval-type) + +Additionally, Chisel defines `Bundles` for making +collections of values with named fields (similar to ```structs``` in +other languages), and ```Vecs``` for indexable collections of +values. + +Bundles and Vecs will be covered later. + +Constant or literal values are expressed using Scala integers or +strings passed to constructors for the types: +```scala +1.U // decimal 1-bit lit from Scala Int. +"ha".U // hexadecimal 4-bit lit from string. +"o12".U // octal 4-bit lit from string. +"b1010".U // binary 4-bit lit from string. + +5.S // signed decimal 4-bit lit from Scala Int. +-8.S // negative decimal 4-bit lit from Scala Int. +5.U // unsigned decimal 3-bit lit from Scala Int. + +8.U(4.W) // 4-bit unsigned decimal, value 8. +-152.S(32.W) // 32-bit signed decimal, value -152. + +true.B // Bool lits from Scala lits. +false.B +``` +Underscores can be used as separators in long string literals to aid +readability, but are ignored when creating the value, e.g.: +```scala +"h_dead_beef".U // 32-bit lit of type UInt +``` + +By default, the Chisel compiler will size each constant to the minimum +number of bits required to hold the constant, including a sign bit for +signed types. Bit widths can also be specified explicitly on +literals, as shown below. Note that (`.W` is used to cast a Scala Int +to a Chisel width) +```scala +"ha".asUInt(8.W) // hexadecimal 8-bit lit of type UInt +"o12".asUInt(6.W) // octal 6-bit lit of type UInt +"b1010".asUInt(12.W) // binary 12-bit lit of type UInt + +5.asSInt(7.W) // signed decimal 7-bit lit of type SInt +5.asUInt(8.W) // unsigned decimal 8-bit lit of type UInt +``` + +For literals of type ```UInt```, the value is +zero-extended to the desired bit width. For literals of type +```SInt```, the value is sign-extended to fill the desired bit width. +If the given bit width is too small to hold the argument value, then a +Chisel error is generated. + +>We are working on a more concise literal syntax for Chisel using +symbolic prefix operators, but are stymied by the limitations of Scala +operator overloading and have not yet settled on a syntax that is +actually more readable than constructors taking strings. + +>We have also considered allowing Scala literals to be automatically +converted to Chisel types, but this can cause type ambiguity and +requires an additional import. + +>The SInt and UInt types will also later support an optional exponent +field to allow Chisel to automatically produce optimized fixed-point +arithmetic circuits. + +## Casting + +We can also cast types in Chisel: + +```scala +val sint = 3.S(4.W) // 4-bit SInt + +val uint = sint.asUInt // cast SInt to UInt +uint.asSInt // cast UInt to SInt +``` + +**NOTE**: `asUInt`/`asSInt` with an explicit width can **not** be used to cast (convert) between Chisel datatypes. +No width parameter is accepted, as Chisel will automatically pad or truncate as required when the objects are connected. + +We can also perform casts on clocks, though you should be careful about this, since clocking (especially in ASIC) requires special attention: + +```scala +val bool: Bool = false.B // always-low wire +val clock = bool.asClock // always-low clock + +clock.asUInt // convert clock to UInt (width 1) +clock.asUInt.asBool // convert clock to Bool (Chisel 3.2+) +clock.asUInt.toBool // convert clock to Bool (Chisel 3.0 and 3.1 only) +``` + +## Analog/BlackBox type + +(Experimental, Chisel 3.1+) + +Chisel supports an `Analog` type (equivalent to Verilog `inout`) that can be used to support arbitrary nets in Chisel. This includes analog wires, tri-state/bi-directional wires, and power nets (with appropriate annotations). + +`Analog` is an undirectioned type, and so it is possible to connect multiple `Analog` nets together using the `attach` operator. It is possible to connect an `Analog` **once** using `<>` but illegal to do it more than once. + +```scala +val a = IO(Analog(1.W)) +val b = IO(Analog(1.W)) +val c = IO(Analog(1.W)) + +// Legal +attach(a, b) +attach(a, c) + +// Legal +a <> b + +// Illegal - connects 'a' multiple times +a <> b +a <> c +``` diff --git a/docs/src/explanations/explanations.md b/docs/src/explanations/explanations.md new file mode 100644 index 00000000..01894ad7 --- /dev/null +++ b/docs/src/explanations/explanations.md @@ -0,0 +1,39 @@ +--- +layout: docs +title: "Explanations" +section: "chisel3" +--- + +# Explanations + +Explanation documentation gives background and context. +They can also explain why things are so - design decisions, +historical reasons, technical constraints. + +If you are just getting started with Chisel, we suggest you +read these documents in the following order: + +* [Motivation](motivation) +* [Supported Hardware](supported-hardware) +* [Data Types](data-types) +* [Bundles and Vecs](bundles-and-vecs) +* [Combinational Circuits](combinational-circuits) +* [Operators](operators) +* [Width Inference](width-inference) +* [Functional Abstraction](functional-abstraction) +* [Ports](ports) +* [Modules](modules) +* [Sequential Circuits](sequential-circuits) +* [Memories](memories) +* [Interfaces and Connections](interfaces-and-connections) +* [Black Boxes](blackboxes) +* [Enumerations](enumerations) +* [Functional Module Creation](functional-module-creation) +* [Muxes and Input Selection](muxes-and-input-selection) +* [Multiple Clock Domains](multi-clock) +* [Reset](reset) +* [Polymorphism and Paramterization](polymorphism-and-parameterization) +* [Printing in Chisel](printing) +* [Naming](naming) +* [Unconnected Wires](unconnected-wires) +* [Annotations](annotations) diff --git a/docs/src/explanations/functional-abstraction.md b/docs/src/explanations/functional-abstraction.md new file mode 100644 index 00000000..4e3900b6 --- /dev/null +++ b/docs/src/explanations/functional-abstraction.md @@ -0,0 +1,34 @@ +--- +layout: docs +title: "Functional Abstraction" +section: "chisel3" +--- + +# Functional Abstraction + +We can define functions to factor out a repeated piece of logic that +we later reuse multiple times in a design. For example, we can wrap +up our earlier example of a simple combinational logic block as +follows: + +```scala mdoc:invisible +import chisel3._ +``` + +```scala mdoc:silent +def clb(a: UInt, b: UInt, c: UInt, d: UInt): UInt = + (a & b) | (~c & d) +``` + +where ```clb``` is the function which takes ```a```, ```b```, +```c```, ```d``` as arguments and returns a wire to the output of a +boolean circuit. The ```def``` keyword is part of Scala and +introduces a function definition, with each argument followed by a colon then its type, +and the function return type given after the colon following the +argument list. The equals (```=})```sign separates the function argument list from the function +definition. + +We can then use the block in another circuit as follows: +```scala mdoc:silent +val out = clb(a,b,c,d) +``` diff --git a/docs/src/explanations/functional-module-creation.md b/docs/src/explanations/functional-module-creation.md new file mode 100644 index 00000000..407edb1d --- /dev/null +++ b/docs/src/explanations/functional-module-creation.md @@ -0,0 +1,120 @@ +--- +layout: docs +title: "Functional Module Creation" +section: "chisel3" +--- + +# Functional Module Creation + +Objects in Scala have a pre-existing creation function (method) called `apply`. +When an object is used as value in an expression (which basically means that the constructor was called), this method determines the returned value. +When dealing with hardware modules, one would expect the module output to be representative of the hardware module's functionality. +Therefore, we would sometimes like the module output to be the value returned when using the object as a value in an expression. +Since hardware modules are represented as Scala objects, this can be done by defining the object's `apply` method to return the module's output. +This can be referred to as creating a functional interface for module construction. +If we apply this on the standard mux2 example, we would to return the mux2 output ports when we used mux2 in an expression. +Implementing this requires building a constructor that takes multiplexer inputs as parameters and returns the multiplexer output: + +```scala mdoc:silent +import chisel3._ + +class Mux2 extends Module { + val io = IO(new Bundle { + val sel = Input(Bool()) + val in0 = Input(UInt()) + val in1 = Input(UInt()) + val out = Output(UInt()) + }) + io.out := Mux(io.sel, io.in0, io.in1) +} + +object Mux2 { + def apply(sel: UInt, in0: UInt, in1: UInt) = { + val m = Module(new Mux2) + m.io.in0 := in0 + m.io.in1 := in1 + m.io.sel := sel + m.io.out + } +} +``` + +As we can see in the code example, we defined the `apply` method to take the Mux2 inputs as the method parameters, and return the Mux2 output as the function's return value. +By defining modules in this way, it is easier to later implement larger and more complex version of this regular module. +For example, we previously implemented Mux4 like this: + +```scala mdoc:silent +class Mux4 extends Module { + val io = IO(new Bundle { + val in0 = Input(UInt(1.W)) + val in1 = Input(UInt(1.W)) + val in2 = Input(UInt(1.W)) + val in3 = Input(UInt(1.W)) + val sel = Input(UInt(2.W)) + val out = Output(UInt(1.W)) + }) + val m0 = Module(new Mux2) + m0.io.sel := io.sel(0) + m0.io.in0 := io.in0 + m0.io.in1 := io.in1 + + val m1 = Module(new Mux2) + m1.io.sel := io.sel(0) + m1.io.in0 := io.in2 + m1.io.in1 := io.in3 + + val m3 = Module(new Mux2) + m3.io.sel := io.sel(1) + m3.io.in0 := m0.io.out + m3.io.in1 := m1.io.out + + io.out := m3.io.out +} +``` + +However, by using the creation function we redefined for Mux2, we can now use the Mux2 outputs as values of the modules themselves +when writing the Mux4 output expression: + +```scala mdoc:invisible:reset +// We need to re-do this to allow us to `reset` +// and then re-define Mux4 +import chisel3._ + +class Mux2 extends Module { + val io = IO(new Bundle { + val sel = Input(Bool()) + val in0 = Input(UInt()) + val in1 = Input(UInt()) + val out = Output(UInt()) + }) + io.out := Mux(io.sel, io.in0, io.in1) +} + +object Mux2 { + def apply(sel: UInt, in0: UInt, in1: UInt) = { + val m = Module(new Mux2) + m.io.in0 := in0 + m.io.in1 := in1 + m.io.sel := sel + m.io.out + } +} +``` + +```scala mdoc:silent +class Mux4 extends Module { + val io = IO(new Bundle { + val in0 = Input(UInt(1.W)) + val in1 = Input(UInt(1.W)) + val in2 = Input(UInt(1.W)) + val in3 = Input(UInt(1.W)) + val sel = Input(UInt(2.W)) + val out = Output(UInt(1.W)) + }) + io.out := Mux2(io.sel(1), + Mux2(io.sel(0), io.in0, io.in1), + Mux2(io.sel(0), io.in2, io.in3)) +} +``` + +This allows us to write more intuitively readable hardware connection descriptions, which are similar to software expression evaluation. diff --git a/docs/src/explanations/interfaces-and-connections.md b/docs/src/explanations/interfaces-and-connections.md new file mode 100644 index 00000000..9f48b642 --- /dev/null +++ b/docs/src/explanations/interfaces-and-connections.md @@ -0,0 +1,149 @@ +--- +layout: docs +title: "Interfaces and Connections" +section: "chisel3" +--- + +# Interfaces & Bulk Connections + +For more sophisticated modules it is often useful to define and instantiate interface classes while defining the IO for a module. First and foremost, interface classes promote reuse allowing users to capture once and for all common interfaces in a useful form. + +Secondly, interfaces allow users to dramatically reduce wiring by supporting bulk connections between producer and consumer modules. Finally, users can make changes in large interfaces in one place reducing the number of updates required when adding or removing pieces of the interface. + +Note that Chisel has some built-in standard interface which should be used whenever possible for interoperability (e.g. Decoupled). + +## Ports: Subclasses & Nesting + +As we saw earlier, users can define their own interfaces by defining a class that subclasses Bundle. For example, a user could define a simple link for hand-shaking data as follows: + +```scala mdoc:invisible +import chisel3._ +``` + +```scala mdoc:silent +class SimpleLink extends Bundle { + val data = Output(UInt(16.W)) + val valid = Output(Bool()) +} +``` + +We can then extend SimpleLink by adding parity bits using bundle inheritance: +```scala mdoc:silent +class PLink extends SimpleLink { + val parity = Output(UInt(5.W)) +} +``` +In general, users can organize their interfaces into hierarchies using inheritance. + +From there we can define a filter interface by nesting two PLinks into a new FilterIO bundle: +```scala mdoc:silent +class FilterIO extends Bundle { + val x = Flipped(new PLink) + val y = new PLink +} +``` +where flip recursively changes the direction of a bundle, changing input to output and output to input. + +We can now define a filter by defining a filter class extending module: +```scala mdoc:silent +class Filter extends Module { + val io = IO(new FilterIO) + // ... +} +``` +where the io field contains FilterIO. + +## Bundle Vectors + +Beyond single elements, vectors of elements form richer hierarchical interfaces. For example, in order to create a crossbar with a vector of inputs, producing a vector of outputs, and selected by a UInt input, we utilize the Vec constructor: +```scala mdoc:silent +import chisel3.util.log2Ceil +class CrossbarIo(n: Int) extends Bundle { + val in = Vec(n, Flipped(new PLink)) + val sel = Input(UInt(log2Ceil(n).W)) + val out = Vec(n, new PLink) +} +``` +where Vec takes a size as the first argument and a block returning a port as the second argument. + +## Bulk Connections + +We can now compose two filters into a filter block as follows: +```scala mdoc:silent +class Block extends Module { + val io = IO(new FilterIO) + val f1 = Module(new Filter) + val f2 = Module(new Filter) + f1.io.x <> io.x + f1.io.y <> f2.io.x + f2.io.y <> io.y +} +``` +where <> bulk connects interfaces of opposite gender between sibling modules or interfaces of the same gender between parent/child modules. + +Bulk connections connect leaf ports of the same name to each other. If the names do not match or are missing, Chisel does not generate a connection. + +Caution: bulk connections should only be used with **directioned elements** (like IOs), and is not magical (e.g. connecting two wires isn't supported since Chisel can't necessarily figure out the directions automatically [chisel3#603](https://github.com/freechipsproject/chisel3/issues/603)). + +## The standard ready-valid interface (ReadyValidIO / Decoupled) + +Chisel provides a standard interface for [ready-valid interfaces](http://inst.eecs.berkeley.edu/~cs150/Documents/Interfaces.pdf). +A ready-valid interface consists of a `ready` signal, a `valid` signal, and some data stored in `bits`. +The `ready` bit indicates that a consumer is *ready* to consume data. +The `valid` bit indicates that a producer has *valid* data on `bits`. +When both `ready` and `valid` are asserted, a data transfer from the producer to the consumer takes place. +A convenience method `fire` is provided that is asserted if both `ready` and `valid` are asserted. + +Usually, we use the utility function [`Decoupled()`](https://chisel.eecs.berkeley.edu/api/latest/chisel3/util/Decoupled$.html) to turn any type into a ready-valid interface rather than directly using [ReadyValidIO](http://chisel.eecs.berkeley.edu/api/latest/chisel3/util/ReadyValidIO.html). + +* `Decoupled(...)` creates a producer / output ready-valid interface (i.e. bits is an output). +* `Flipped(Decoupled(...))` creates a consumer / input ready-valid interface (i.e. bits is an input). + +Take a look at the following example Chisel code to better understand exactly what is generated: + +```scala mdoc:silent:reset +import chisel3._ +import chisel3.util.Decoupled + +/** + * Using Decoupled(...) creates a producer interface. + * i.e. it has bits as an output. + * This produces the following ports: + * input io_readyValid_ready, + * output io_readyValid_valid, + * output [31:0] io_readyValid_bits + */ +class ProducingData extends Module { + val io = IO(new Bundle { + val readyValid = Decoupled(UInt(32.W)) + }) + // do something with io.readyValid.ready + io.readyValid.valid := true.B + io.readyValid.bits := 5.U +} + +/** + * Using Flipped(Decoupled(...)) creates a consumer interface. + * i.e. it has bits as an input. + * This produces the following ports: + * output io_readyValid_ready, + * input io_readyValid_valid, + * input [31:0] io_readyValid_bits + */ +class ConsumingData extends Module { + val io = IO(new Bundle { + val readyValid = Flipped(Decoupled(UInt(32.W))) + }) + io.readyValid.ready := false.B + // do something with io.readyValid.valid + // do something with io.readyValid.bits +} +``` + +`DecoupledIO` is a ready-valid interface with the *convention* that there are no guarantees placed on deasserting `ready` or `valid` or on the stability of `bits`. +That means `ready` and `valid` can also be deasserted without a data transfer. + +`IrrevocableIO` is a ready-valid interface with the *convention* that the value of `bits` will not change while `valid` is asserted and `ready` is deasserted. +Also the consumer shall keep `ready` asserted after a cycle where `ready` was high and `valid` was low. +Note that the *irrevocable* constraint *is only a convention* and cannot be enforced by the interface. +Chisel does not automatically generate checkers or assertions to enforce the *irrevocable* convention. diff --git a/docs/src/explanations/memories.md b/docs/src/explanations/memories.md new file mode 100644 index 00000000..792d176e --- /dev/null +++ b/docs/src/explanations/memories.md @@ -0,0 +1,176 @@ +--- +layout: docs +title: "Memories" +section: "chisel3" +--- + +# Memories + +Chisel provides facilities for creating both read only and read/write memories. + +## ROM + +Users can define read only memories with a `Vec`: +```scala mdoc:invisible +import chisel3._ +``` +``` scala mdoc:compile-only + VecInit(inits: Seq[T]) + VecInit(elt0: T, elts: T*) +``` + +where `inits` is a sequence of initial `Data` literals that initialize the ROM. For example, users cancreate a small ROM initialized to 1, 2, 4, 8 and loop through all values using a counter as an address generator as follows: + +``` scala mdoc:compile-only + val m = VecInit(Array(1.U, 2.U, 4.U, 8.U)) + val r = m(counter(m.length.U)) +``` + +We can create an *n* value sine lookup table using a ROM initialized as follows: + +``` scala mdoc:silent + def sinTable(amp: Double, n: Int) = { + val times = + (0 until n).map(i => (i*2*Pi)/(n.toDouble-1) - Pi) + val inits = + times.map(t => round(amp * sin(t)).asSInt(32.W)) + VecInit(inits) + } + def sinWave(amp: Double, n: Int) = + sinTable(amp, n)(counter(n.U)) +``` + +where `amp` is used to scale the fixpoint values stored in the ROM. + +## Read-Write Memories + +Memories are given special treatment in Chisel since hardware implementations of memory vary greatly. For example, FPGA memories are instantiated quite differently from ASIC memories. Chisel defines a memory abstraction that can map to either simple Verilog behavioural descriptions or to instances of memory modules that are available from external memory generators provided by foundry or IP vendors. + + +### `SyncReadMem`: sequential/synchronous-read, sequential/synchronous-write + +Chisel has a construct called `SyncReadMem` for sequential/synchronous-read, sequential/synchronous-write memories. These `SyncReadMem`s will likely be synthesized to technology SRAMs (as opposed to register banks). + +If the same memory address is both written and sequentially read on the same clock edge, or if a sequential read enable is cleared, then the read data is undefined. + +Values on the read data port are not guaranteed to be held until the next read cycle. If that is the desired behavior, external logic to hold the last read value must be added. + +#### Read port/write port +Ports into `SyncReadMem`s are created by applying a `UInt` index. A 1024-entry SRAM with one write port and one read port might be expressed as follows: + +```scala mdoc:silent +import chisel3._ +class ReadWriteSmem extends Module { + val width: Int = 32 + val io = IO(new Bundle { + val enable = Input(Bool()) + val write = Input(Bool()) + val addr = Input(UInt(10.W)) + val dataIn = Input(UInt(width.W)) + val dataOut = Output(UInt(width.W)) + }) + + val mem = SyncReadMem(1024, UInt(width.W)) + // Create one write port and one read port + mem.write(io.addr, io.dataIn) + io.dataOut := mem.read(io.addr, io.enable) +} +``` + +Below is an example waveform of the one write port/one read port `SyncReadMem` with [masks](#masks). Note that the signal names will differ from the exact wire names generated for the `SyncReadMem`. With masking, it is also possible that multiple RTL arrays will be generated with the behavior below. + +![read/write ports example waveform](https://svg.wavedrom.com/github/freechipsproject/www.chisel-lang.org/master/docs/src/main/tut/chisel3/memories_waveforms/smem_read_write.json) + +#### Single-ported +Single-ported SRAMs can be inferred when the read and write conditions are mutually exclusive in the same `when` chain: + +```scala mdoc:silent +import chisel3._ +class RWSmem extends Module { + val width: Int = 32 + val io = IO(new Bundle { + val enable = Input(Bool()) + val write = Input(Bool()) + val addr = Input(UInt(10.W)) + val dataIn = Input(UInt(width.W)) + val dataOut = Output(UInt(width.W)) + }) + + val mem = SyncReadMem(1024, UInt(width.W)) + io.dataOut := DontCare + when(io.enable) { + val rdwrPort = mem(io.addr) + when (io.write) { rdwrPort := io.dataIn } + .otherwise { io.dataOut := rdwrPort } + } +} +``` + +(The `DontCare` is there to make Chisel's [unconnected wire detection](unconnected-wires) aware that reading while writing is undefined.) + +Here is an example single read/write port waveform, with [masks](#masks) (again, generated signal names and number of arrays may differ): + +![read/write ports example waveform](https://svg.wavedrom.com/github/freechipsproject/www.chisel-lang.org/master/docs/src/main/tut/chisel3/memories_waveforms/smem_rw.json) + +### `Mem`: combinational/asynchronous-read, sequential/synchronous-write + +Chisel supports random-access memories via the `Mem` construct. Writes to `Mem`s are combinational/asynchronous-read, sequential/synchronous-write. These `Mem`s will likely be synthesized to register banks, since most SRAMs in modern technologies (FPGA, ASIC) tend to no longer support combinational (asynchronous) reads. + +Creating asynchronous-read versions of the examples above simply involves replacing `SyncReadMem` with `Mem`. + +### Masks + +Chisel memories also support write masks for subword writes. Chisel will infer masks if the data type of the memory is a vector. To infer a mask, specify the `mask` argument of the `write` function which creates write ports. A given masked length is written if the corresponding mask bit is set. For example, in the example below, if the 0th bit of mask is true, it will write the lower byte of the data at corresponding address. + +```scala mdoc:silent +import chisel3._ +class MaskedReadWriteSmem extends Module { + val width: Int = 8 + val io = IO(new Bundle { + val enable = Input(Bool()) + val write = Input(Bool()) + val addr = Input(UInt(10.W)) + val mask = Input(Vec(4, Bool())) + val dataIn = Input(Vec(4, UInt(width.W))) + val dataOut = Output(Vec(4, UInt(width.W))) + }) + + // Create a 32-bit wide memory that is byte-masked + val mem = SyncReadMem(1024, Vec(4, UInt(width.W))) + // Write with mask + mem.write(io.addr, io.dataIn, io.mask) + io.dataOut := mem.read(io.addr, io.enable) +} +``` + +Here is an example of masks with readwrite ports: + +```scala mdoc:silent +import chisel3._ +class MaskedRWSmem extends Module { + val width: Int = 32 + val io = IO(new Bundle { + val enable = Input(Bool()) + val write = Input(Bool()) + val mask = Input(Vec(2, Bool())) + val addr = Input(UInt(10.W)) + val dataIn = Input(Vec(2, UInt(width.W))) + val dataOut = Output(Vec(2, UInt(width.W))) + }) + + val mem = SyncReadMem(1024, Vec(2, UInt(width.W))) + io.dataOut := DontCare + when(io.enable) { + val rdwrPort = mem(io.addr) + when (io.write) { + when(io.mask(0)) { + rdwrPort(0) := io.dataIn(0) + } + when(io.mask(1)) { + rdwrPort(1) := io.dataIn(1) + } + }.otherwise { io.dataOut := rdwrPort } + } +} +``` + diff --git a/docs/src/explanations/modules.md b/docs/src/explanations/modules.md new file mode 100644 index 00000000..32cbff2e --- /dev/null +++ b/docs/src/explanations/modules.md @@ -0,0 +1,138 @@ +--- +layout: docs +title: "Modules" +section: "chisel3" +--- + +# Modules + +Chisel *modules* are very similar to Verilog *modules* in +defining a hierarchical structure in the generated circuit. + +The hierarchical module namespace is accessible in downstream tools +to aid in debugging and physical layout. A user-defined module is +defined as a *class* which: + + - inherits from `Module`, + - contains at least one interface wrapped in a Module's `IO()` method (traditionally stored in a port field named ```io```), and + - wires together subcircuits in its constructor. + +As an example, consider defining your own two-input multiplexer as a +module: +```scala mdoc:silent +import chisel3._ +class Mux2IO extends Bundle { + val sel = Input(UInt(1.W)) + val in0 = Input(UInt(1.W)) + val in1 = Input(UInt(1.W)) + val out = Output(UInt(1.W)) +} + +class Mux2 extends Module { + val io = IO(new Mux2IO) + io.out := (io.sel & io.in1) | (~io.sel & io.in0) +} +``` + +The wiring interface to a module is a collection of ports in the +form of a ```Bundle```. The interface to the module is defined +through a field named ```io```. For ```Mux2```, ```io``` is +defined as a bundle with four fields, one for each multiplexer port. + +The ```:=``` assignment operator, used here in the body of the +definition, is a special operator in Chisel that wires the input of +left-hand side to the output of the right-hand side. + +### Module Hierarchy + +We can now construct circuit hierarchies, where we build larger modules out +of smaller sub-modules. For example, we can build a 4-input +multiplexer module in terms of the ```Mux2``` module by wiring +together three 2-input multiplexers: + +```scala mdoc:silent +class Mux4IO extends Bundle { + val in0 = Input(UInt(1.W)) + val in1 = Input(UInt(1.W)) + val in2 = Input(UInt(1.W)) + val in3 = Input(UInt(1.W)) + val sel = Input(UInt(2.W)) + val out = Output(UInt(1.W)) +} +class Mux4 extends Module { + val io = IO(new Mux4IO) + + val m0 = Module(new Mux2) + m0.io.sel := io.sel(0) + m0.io.in0 := io.in0 + m0.io.in1 := io.in1 + + val m1 = Module(new Mux2) + m1.io.sel := io.sel(0) + m1.io.in0 := io.in2 + m1.io.in1 := io.in3 + + val m3 = Module(new Mux2) + m3.io.sel := io.sel(1) + m3.io.in0 := m0.io.out + m3.io.in1 := m1.io.out + + io.out := m3.io.out +} +``` + +We again define the module interface as ```io``` and wire up the +inputs and outputs. In this case, we create three ```Mux2``` +children modules, using the ```Module``` constructor function and +the Scala ```new``` keyword to create a +new object. We then wire them up to one another and to the ports of +the ```Mux4``` interface. + +Note: Chisel `Module`s have an implicit clock (called `clock`) and +an implicit reset (called `reset`). To create modules without implicit +clock and reset, Chisel provides `RawModule`. + +> Historical Note: Prior to Chisel 3.5, Modules were restricted to only +having a single user-defined port named `io`. There was also a type called +`MultiIOModule` that provided implicit clock and reset while allowing the +user to define as many ports as they want. This is now the functionality +of `Module`. + +### `RawModule` + +A `RawModule` is a module that **does not provide an implicit clock and reset.** +This can be useful when interfacing a Chisel module with a design that expects +a specific naming convention for clock or reset. + +Then we can use it in place of *Module* usage : +```scala mdoc:silent +import chisel3.{RawModule, withClockAndReset} + +class Foo extends Module { + val io = IO(new Bundle{ + val a = Input(Bool()) + val b = Output(Bool()) + }) + io.b := !io.a +} + +class FooWrapper extends RawModule { + val a_i = IO(Input(Bool())) + val b_o = IO(Output(Bool())) + val clk = Input(Clock()) + val rstn = Input(Bool()) + + val foo = withClockAndReset(clk, !rstn){ Module(new Foo) } + + foo.io.a := a_i + b_o := foo.io.b +} +``` + +In the example above, the `RawModule` is used to change the reset polarity +of module `SlaveSpi`. Indeed, the reset is active high by default in Chisel +modules, then using `withClockAndReset(clock, !rstn)` we can use an active low +reset in entire design. + +The clock is just wired as it, but if needed, `RawModule` can be used in +conjunction with `BlackBox` to connect a differential clock input for example. diff --git a/docs/src/explanations/motivation.md b/docs/src/explanations/motivation.md new file mode 100644 index 00000000..afe02a7b --- /dev/null +++ b/docs/src/explanations/motivation.md @@ -0,0 +1,44 @@ +--- +layout: docs +title: "Motivation" +section: "chisel3" +--- + +# Motivation -- "Why Chisel?" + +We were motivated to develop a new hardware language by years of +struggle with existing hardware description languages in our research +projects and hardware design courses. _Verilog_ and _VHDL_ were developed +as hardware _simulation_ languages, and only later did they become +a basis for hardware _synthesis_. Much of the semantics of these +languages are not appropriate for hardware synthesis and, in fact, +many constructs are simply not synthesizable. Other constructs are +non-intuitive in how they map to hardware implementations, or their +use can accidentally lead to highly inefficient hardware structures. +While it is possible to use a subset of these languages and still get +acceptable results, they nonetheless present a cluttered and confusing +specification model, particularly in an instructional setting. + +However, our strongest motivation for developing a new hardware +language is our desire to change the way that electronic system design +takes place. We believe that it is important to not only teach +students how to design circuits, but also to teach them how to design +*circuit generators* ---programs that automatically generate +designs from a high-level set of design parameters and constraints. +Through circuit generators, we hope to leverage the hard work of +design experts and raise the level of design abstraction for everyone. +To express flexible and scalable circuit construction, circuit +generators must employ sophisticated programming techniques to make +decisions concerning how to best customize their output circuits +according to high-level parameter values and constraints. While +Verilog and VHDL include some primitive constructs for programmatic +circuit generation, they lack the powerful facilities present in +modern programming languages, such as object-oriented programming, +type inference, support for functional programming, and reflection. + +Instead of building a new hardware design language from scratch, we +chose to embed hardware construction primitives within an existing +language. We picked Scala not only because it includes the +programming features we feel are important for building circuit +generators, but because it was specifically developed as a base for +domain-specific languages. diff --git a/docs/src/explanations/muxes-and-input-selection.md b/docs/src/explanations/muxes-and-input-selection.md new file mode 100644 index 00000000..ae087e83 --- /dev/null +++ b/docs/src/explanations/muxes-and-input-selection.md @@ -0,0 +1,62 @@ +--- +layout: docs +title: "Muxes and Input Selection" +section: "chisel3" +--- + +# Muxes and Input Selection + +Selecting inputs is very useful in hardware description, and therefore Chisel provides several built-in generic input-selection implementations. + +### Mux +The first one is `Mux`. This is a 2-input selector. Unlike the `Mux2` example which was presented previously, the built-in `Mux` allows +the inputs (`in0` and `in1`) to be any datatype as long as they are the same subclass of `Data`. + +By using the functional module creation feature presented in the previous section, we can create multi-input selector in a simple way: + +```scala +Mux(c1, a, Mux(c2, b, Mux(..., default))) +``` + +### MuxCase + +The nested `Mux` is not necessary since Chisel also provides the built-in `MuxCase`, which implements that exact feature. +`MuxCase` is an n-way `Mux`, which can be used as follows: + +```scala +MuxCase(default, Array(c1 -> a, c2 -> b, ...)) +``` + +Where each selection dependency is represented as a tuple in a Scala +array [ condition -> selected_input_port ]. + +### MuxLookup +Chisel also provides `MuxLookup` which is an n-way indexed multiplexer: + +```scala +MuxLookup(idx, default, + Array(0.U -> a, 1.U -> b, ...)) +``` + +This is the same as a `MuxCase`, where the conditions are all index based selection: + +```scala +MuxCase(default, + Array((idx === 0.U) -> a, + (idx === 1.U) -> b, ...)) +``` + +Note that the conditions/cases/selectors (eg. c1, c2) must be in parentheses. + +### Mux1H +Another ```Mux``` utility is the one-hot mux, ```Mux1H```. It takes a sequence of selectors and values and returns the value associated with the one selector that is set. If zero or multiple selectors are set the behavior is undefined. For example: + +```scala + val hotValue = chisel3.util.Mux1H(Seq( + io.selector(0) -> 2.U, + io.selector(1) -> 4.U, + io.selector(2) -> 8.U, + io.selector(4) -> 11.U, + )) +``` +```Mux1H``` whenever possible generates *Firrtl* that is readily optimizable as low depth and/or tree. This optimization is not possible when the values are of type ```FixedPoint``` or an aggregate type that contains ```FixedPoint```s and results instead as a simple ```Mux``` tree. This behavior could be sub-optimal. As ```FixedPoint``` is still *experimental* this behavior may change in the future. diff --git a/docs/src/explanations/operators.md b/docs/src/explanations/operators.md new file mode 100644 index 00000000..231a53fa --- /dev/null +++ b/docs/src/explanations/operators.md @@ -0,0 +1,65 @@ +--- +layout: docs +title: "Operators" +section: "chisel3" +--- + +# Chisel Operators + +Chisel defines a set of hardware operators: + +| Operation | Explanation | +| --------- | --------- | +| **Bitwise operators** | **Valid on:** SInt, UInt, Bool | +| `val invertedX = ~x` | Bitwise NOT | +| `val hiBits = x & "h_ffff_0000".U` | Bitwise AND | +| `val flagsOut = flagsIn \| overflow` | Bitwise OR | +| `val flagsOut = flagsIn ^ toggle` | Bitwise XOR | +| **Bitwise reductions.** | **Valid on:** SInt and UInt. Returns Bool. | +| `val allSet = x.andR` | AND reduction | +| `val anySet = x.orR` | OR reduction | +| `val parity = x.xorR` | XOR reduction | +| **Equality comparison.** | **Valid on:** SInt, UInt, and Bool. Returns Bool. | +| `val equ = x === y` | Equality | +| `val neq = x =/= y` | Inequality | +| **Shifts** | **Valid on:** SInt and UInt | +| `val twoToTheX = 1.S << x` | Logical shift left | +| `val hiBits = x >> 16.U` | Right shift (logical on UInt and arithmetic on SInt). | +| **Bitfield manipulation** | **Valid on:** SInt, UInt, and Bool. | +| `val xLSB = x(0)` | Extract single bit, LSB has index 0. | +| `val xTopNibble = x(15, 12)` | Extract bit field from end to start bit position. | +| `val usDebt = Fill(3, "hA".U)` | Replicate a bit string multiple times. | +| `val float = Cat(sign, exponent, mantissa)` | Concatenates bit fields, with first argument on left. | +| **Logical Operations** | **Valid on:** Bool +| `val sleep = !busy` | Logical NOT | +| `val hit = tagMatch && valid` | Logical AND | +| `val stall = src1busy || src2busy` | Logical OR | +| `val out = Mux(sel, inTrue, inFalse)` | Two-input mux where sel is a Bool | +| **Arithmetic operations** | **Valid on Nums:** SInt and UInt. | +| `val sum = a + b` *or* `val sum = a +% b` | Addition (without width expansion) | +| `val sum = a +& b` | Addition (with width expansion) | +| `val diff = a - b` *or* `val diff = a -% b` | Subtraction (without width expansion) | +| `val diff = a -& b` | Subtraction (with width expansion) | +| `val prod = a * b` | Multiplication | +| `val div = a / b` | Division | +| `val mod = a % b` | Modulus | +| **Arithmetic comparisons** | **Valid on Nums:** SInt and UInt. Returns Bool. | +| `val gt = a > b` | Greater than | +| `val gte = a >= b` | Greater than or equal | +| `val lt = a < b` | Less than | +| `val lte = a <= b` | Less than or equal | + +>Our choice of operator names was constrained by the Scala language. +We have to use triple equals```===``` for equality and ```=/=``` +for inequality to allow the +native Scala equals operator to remain usable. + +The Chisel operator precedence is not directly defined as part of the Chisel language. +Practically, it is determined by the evaluation order of the circuit, +which natuarally follows the [Scala operator precedence](https://docs.scala-lang.org/tour/operators.html). +If in doubt of operator precedence, use parentheses. + +> The Chisel/Scala operator precedence is similar but +not identical to precedence in Java or C. Verilog has the same operator precedence as C, but VHDL +does not. Verilog has precedence ordering for logic operations, but in VHDL +those operators have the same precedence and are evaluated from left to right. diff --git a/docs/src/explanations/polymorphism-and-parameterization.md b/docs/src/explanations/polymorphism-and-parameterization.md new file mode 100644 index 00000000..94b896b1 --- /dev/null +++ b/docs/src/explanations/polymorphism-and-parameterization.md @@ -0,0 +1,237 @@ +--- +layout: docs +title: "Polymorphism and Parameterization" +section: "chisel3" +--- + +# Polymorphism and Paramterization + +_This section is advanced and can be skipped at first reading._ + +Scala is a strongly typed language and uses parameterized types to specify generic functions and classes. +In this section, we show how Chisel users can define their own reusable functions and classes using parameterized classes. + +## Parameterized Functions + +Earlier we defined `Mux2` on `Bool`, but now we show how we can define a generic multiplexer function. +We define this function as taking a boolean condition and con and alt arguments (corresponding to then and else expressions) of type `T`: + +```scala +def Mux[T <: Bits](c: Bool, con: T, alt: T): T = { ... } +``` + +where `T` is required to be a subclass of `Bits`. +Scala ensures that in each usage of `Mux`, it can find a common superclass of the actual con and alt argument types, +otherwise it causes a Scala compilation type error. +For example, + +```scala +Mux(c, UInt(10), UInt(11)) +``` + +yields a `UInt` wire because the `con` and `alt` arguments are each of type `UInt`. + + + +## Parameterized Classes + +Like parameterized functions, we can also parameterize classes to make them more reusable. +For instance, we can generalize the Filter class to use any kind of link. +We do so by parameterizing the `FilterIO` class and defining the constructor to take a single argument `gen` of type `T` as below. +```scala mdoc:invisible +import chisel3._ +``` +```scala mdoc:silent +class FilterIO[T <: Data](gen: T) extends Bundle { + val x = Input(gen) + val y = Output(gen) +} +``` + +We can now define `Filter` by defining a module class that also takes a link type constructor argument and passes it through to the `FilterIO` interface constructor: + +```scala mdoc:silent +class Filter[T <: Data](gen: T) extends Module { + val io = IO(new FilterIO(gen)) + // ... +} +``` + +We can now define a `PLink`-based `Filter` as follows: +```scala mdoc:invisible +class SimpleLink extends Bundle { + val data = Output(UInt(16.W)) + val valid = Output(Bool()) +} +class PLink extends SimpleLink { + val parity = Output(UInt(5.W)) +} +``` +```scala mdoc:compile-only +val f = Module(new Filter(new PLink)) +``` + +A generic FIFO could be defined as follows: + +```scala mdoc:silent +import chisel3.util.log2Up + +class DataBundle extends Bundle { + val a = UInt(32.W) + val b = UInt(32.W) +} + +class Fifo[T <: Data](gen: T, n: Int) extends Module { + val io = IO(new Bundle { + val enqVal = Input(Bool()) + val enqRdy = Output(Bool()) + val deqVal = Output(Bool()) + val deqRdy = Input(Bool()) + val enqDat = Input(gen) + val deqDat = Output(gen) + }) + val enqPtr = RegInit(0.U((log2Up(n)).W)) + val deqPtr = RegInit(0.U((log2Up(n)).W)) + val isFull = RegInit(false.B) + val doEnq = io.enqRdy && io.enqVal + val doDeq = io.deqRdy && io.deqVal + val isEmpty = !isFull && (enqPtr === deqPtr) + val deqPtrInc = deqPtr + 1.U + val enqPtrInc = enqPtr + 1.U + val isFullNext = Mux(doEnq && ~doDeq && (enqPtrInc === deqPtr), + true.B, Mux(doDeq && isFull, false.B, + isFull)) + enqPtr := Mux(doEnq, enqPtrInc, enqPtr) + deqPtr := Mux(doDeq, deqPtrInc, deqPtr) + isFull := isFullNext + val ram = Mem(n, gen) + when (doEnq) { + ram(enqPtr) := io.enqDat + } + io.enqRdy := !isFull + io.deqVal := !isEmpty + ram(deqPtr) <> io.deqDat +} +``` + +An Fifo with 8 elements of type DataBundle could then be instantiated as: + +```scala mdoc:compile-only +val fifo = Module(new Fifo(new DataBundle, 8)) +``` + +It is also possible to define a generic decoupled (ready/valid) interface: +```scala mdoc:invisible:reset +import chisel3._ +class DataBundle extends Bundle { + val a = UInt(32.W) + val b = UInt(32.W) +} +``` + +```scala mdoc:silent +class DecoupledIO[T <: Data](data: T) extends Bundle { + val ready = Input(Bool()) + val valid = Output(Bool()) + val bits = Output(data) +} +``` + +This template can then be used to add a handshaking protocol to any +set of signals: + +```scala mdoc:silent +class DecoupledDemo extends DecoupledIO(new DataBundle) +``` + +The FIFO interface can be now be simplified as follows: + +```scala mdoc:silent +class Fifo[T <: Data](data: T, n: Int) extends Module { + val io = IO(new Bundle { + val enq = Flipped(new DecoupledIO(data)) + val deq = new DecoupledIO(data) + }) + // ... +} +``` + +## Parametrization based on Modules + +You can also parametrize modules based on other modules rather than just types. The following is an example of a module parametrized by other modules as opposed to e.g. types. + +```scala mdoc:silent +import chisel3.RawModule +import chisel3.experimental.BaseModule +import chisel3.stage.ChiselStage + +// Provides a more specific interface since generic Module +// provides no compile-time information on generic module's IOs. +trait MyAdder { + def in1: UInt + def in2: UInt + def out: UInt +} + +class Mod1 extends RawModule with MyAdder { + val in1 = IO(Input(UInt(8.W))) + val in2 = IO(Input(UInt(8.W))) + val out = IO(Output(UInt(8.W))) + out := in1 + in2 +} + +class Mod2 extends RawModule with MyAdder { + val in1 = IO(Input(UInt(8.W))) + val in2 = IO(Input(UInt(8.W))) + val out = IO(Output(UInt(8.W))) + out := in1 - in2 +} + +class X[T <: BaseModule with MyAdder](genT: => T) extends Module { + val io = IO(new Bundle { + val in1 = Input(UInt(8.W)) + val in2 = Input(UInt(8.W)) + val out = Output(UInt(8.W)) + }) + val subMod = Module(genT) + io.out := subMod.out + subMod.in1 := io.in1 + subMod.in2 := io.in2 +} + +println(ChiselStage.emitVerilog(new X(new Mod1))) +println(ChiselStage.emitVerilog(new X(new Mod2))) +``` +```scala mdoc:passthrough +println(ChiselStage.emitVerilog(new X(new Mod1))) +println(ChiselStage.emitVerilog(new X(new Mod2))) +``` diff --git a/docs/src/explanations/ports.md b/docs/src/explanations/ports.md new file mode 100644 index 00000000..ce38cf22 --- /dev/null +++ b/docs/src/explanations/ports.md @@ -0,0 +1,67 @@ +--- +layout: docs +title: "Ports" +section: "chisel3" +--- + +# Ports + +Ports are used as interfaces to hardware components. A port is simply +any `Data` object that has directions assigned to its members. + +Chisel provides port constructors to allow a direction to be added +(input or output) to an object at construction time. Primitive port +constructors wrap the type of the port in `Input` or `Output`. + +An example port declaration is as follows: +```scala mdoc:invisible +import chisel3._ +``` +```scala mdoc +class Decoupled extends Bundle { + val ready = Output(Bool()) + val data = Input(UInt(32.W)) + val valid = Input(Bool()) +} +``` + +After defining ```Decoupled```, it becomes a new type that can be +used as needed for module interfaces or for named collections of +wires. + +By folding directions into the object declarations, Chisel is able to +provide powerful wiring constructs described later. + +## Inspecting Module ports + +(Chisel 3.2+) + +Chisel 3.2 introduced `DataMirror.modulePorts` which can be used to inspect the IOs of any Chisel module (this includes modules in both `import chisel3._` and `import Chisel._`, as well as BlackBoxes from each package). +Here is an example of how to use this API: + +```scala mdoc +import chisel3.experimental.DataMirror +import chisel3.stage.{ChiselGeneratorAnnotation, ChiselStage} + +class Adder extends Module { + val a = IO(Input(UInt(8.W))) + val b = IO(Input(UInt(8.W))) + val c = IO(Output(UInt(8.W))) + c := a +& b +} + +class Test extends Module { + val adder = Module(new Adder) + // for debug only + adder.a := DontCare + adder.b := DontCare + + // Inspect ports of adder + // See the result below. + DataMirror.modulePorts(adder).foreach { case (name, port) => { + println(s"Found port $name: $port") + }} +} + +(new ChiselStage).execute(Array.empty, Seq(ChiselGeneratorAnnotation(() => new Test))) +``` \ No newline at end of file diff --git a/docs/src/explanations/printing.md b/docs/src/explanations/printing.md new file mode 100644 index 00000000..abd1a427 --- /dev/null +++ b/docs/src/explanations/printing.md @@ -0,0 +1,137 @@ +--- +layout: docs +title: "Printing" +section: "chisel3" +--- + +# Printing in Chisel + +Chisel provides the `printf` function for debugging purposes. It comes in two flavors: + +* [Scala-style](#scala-style) +* [C-style](#c-style) + +### Scala-style + +Chisel also supports printf in a style similar to [Scala's String Interpolation](http://docs.scala-lang.org/overviews/core/string-interpolation.html). Chisel provides a custom string interpolator `p` which can be used as follows: + +```scala mdoc:invisible +import chisel3._ +``` +```scala mdoc:compile-only +val myUInt = 33.U +printf(p"myUInt = $myUInt") // myUInt = 33 +``` + +Note that when concatenating `p"..."` strings, you need to start with a `p"..."` string: + +```scala mdoc:compile-only +// Does not interpolate the second string +val myUInt = 33.U +printf("my normal string" + p"myUInt = $myUInt") +``` + +#### Simple formatting + +Other formats are available as follows: + +```scala mdoc:compile-only +val myUInt = 33.U +// Hexadecimal +printf(p"myUInt = 0x${Hexadecimal(myUInt)}") // myUInt = 0x21 +// Binary +printf(p"myUInt = ${Binary(myUInt)}") // myUInt = 100001 +// Character +printf(p"myUInt = ${Character(myUInt)}") // myUInt = ! +``` + +We recognize that the format specifiers are verbose, so we are working on a more concise syntax. + +#### Aggregate data-types + +Chisel provides default custom "pretty-printing" for Vecs and Bundles. The default printing of a Vec is similar to printing a Seq or List in Scala while printing a Bundle is similar to printing a Scala Map. + +```scala mdoc:compile-only +val myVec = VecInit(5.U, 10.U, 13.U) +printf(p"myVec = $myVec") // myVec = Vec(5, 10, 13) + +val myBundle = Wire(new Bundle { + val foo = UInt() + val bar = UInt() +}) +myBundle.foo := 3.U +myBundle.bar := 11.U +printf(p"myBundle = $myBundle") // myBundle = Bundle(a -> 3, b -> 11) +``` + +#### Custom Printing + +Chisel also provides the ability to specify _custom_ printing for user-defined Bundles. + +```scala mdoc:compile-only +class Message extends Bundle { + val valid = Bool() + val addr = UInt(32.W) + val length = UInt(4.W) + val data = UInt(64.W) + override def toPrintable: Printable = { + val char = Mux(valid, 'v'.U, '-'.U) + p"Message:\n" + + p" valid : ${Character(char)}\n" + + p" addr : 0x${Hexadecimal(addr)}\n" + + p" length : $length\n" + + p" data : 0x${Hexadecimal(data)}\n" + } +} + +val myMessage = Wire(new Message) +myMessage.valid := true.B +myMessage.addr := "h1234".U +myMessage.length := 10.U +myMessage.data := "hdeadbeef".U + +printf(p"$myMessage") +``` + +Which prints the following: + +``` +Message: + valid : v + addr : 0x00001234 + length : 10 + data : 0x00000000deadbeef +``` + +Notice the use of `+` between `p` interpolated "strings". The results of `p` interpolation can be concatenated by using the `+` operator. For more information, please see the documentation + +### C-Style + +Chisel provides `printf` in a similar style to its C namesake. It accepts a double-quoted format string and a variable number of arguments which will then be printed on rising clock edges. Chisel supports the following format specifiers: + +| Format Specifier | Meaning | +| :-----: | :-----: | +| `%d` | decimal number | +| `%x` | hexadecimal number | +| `%b` | binary number | +| `%c` | 8-bit ASCII character | +| `%%` | literal percent | + +It also supports a small set of escape characters: + +| Escape Character | Meaning | +| :-----: | :-----: | +| `\n` | newline | +| `\t` | tab | +| `\"` | literal double quote | +| `\'` | literal single quote | +| `\\` | literal backslash | + +Note that single quotes do not require escaping, but are legal to escape. + +Thus printf can be used in a way very similar to how it is used in C: + +```scala mdoc:compile-only +val myUInt = 32.U +printf("myUInt = %d", myUInt) // myUInt = 32 +``` diff --git a/docs/src/explanations/reset.md b/docs/src/explanations/reset.md new file mode 100644 index 00000000..a99a39e3 --- /dev/null +++ b/docs/src/explanations/reset.md @@ -0,0 +1,179 @@ +--- +layout: docs +title: "Reset" +section: "chisel3" +--- + +# Reset + +```scala mdoc:invisible +import chisel3._ + +class Submodule extends Module +``` + +As of Chisel 3.2.0, Chisel 3 supports both synchronous and asynchronous reset, +meaning that it can natively emit both synchronous and asynchronously reset registers. + +The type of register that is emitted is based on the type of the reset signal associated +with the register. + +There are three types of reset that implement a common trait `Reset`: +* `Bool` - constructed with `Bool()`. Also known as "synchronous reset". +* `AsyncReset` - constructed with `AsyncReset()`. Also known as "asynchronous reset". +* `Reset` - constructed with `Reset()`. Also known as "abstract reset". + +For implementation reasons, the concrete Scala type is `ResetType`. Stylistically we avoid `ResetType`, instead using the common trait `Reset`. + +Registers with reset signals of type `Bool` are emitted as synchronous reset flops. +Registers with reset signals of type `AsyncReset` are emitted as asynchronouly reset flops. +Registers with reset signals of type `Reset` will have their reset type _inferred_ during FIRRTL compilation. + +### Reset Inference + +FIRRTL will infer a concrete type for any signals of type abstract `Reset`. +The rules are as follows: +1. An abstract `Reset` with only signals of type `AsyncReset`, abstract `Reset`, and `DontCare` +in both its fan-in and fan-out will infer to be of type `AsyncReset` +2. An abstract `Reset` with signals of both types `Bool` and `AsyncReset` in its fan-in and fan-out +is an error. +3. Otherwise, an abstract `Reset` will infer to type `Bool`. + +You can think about (3) as the mirror of (1) replacing `AsyncReset` with `Bool` with the additional +rule that abstract `Reset`s with neither `AsyncReset` nor `Bool` in their fan-in and fan-out will +default to type `Bool`. +This "default" case is uncommon and implies that reset signal is ultimately driven by a `DontCare`. + +### Implicit Reset + +A `Module`'s `reset` is of type abstract `Reset`. +Prior to Chisel 3.2.0, the type of this field was `Bool`. +For backwards compatability, if the top-level module has an implicit reset, its type will default to `Bool`. + +#### Setting Implicit Reset Type + +_New in Chisel 3.3.0_ + +If you would like to set the reset type from within a Module (including the top-level `Module`), +rather than relying on _Reset Inference_, you can mixin one of the following traits: +* `RequireSyncReset` - sets the type of `reset` to `Bool` +* `RequireAsyncReset` - sets the type of `reset` to `AsyncReset` + +For example: + +```scala mdoc:silent +class MyAlwaysSyncResetModule extends Module with RequireSyncReset { + val mySyncResetReg = RegInit(false.B) // reset is of type Bool +} +``` + +```scala mdoc:silent +class MyAlwaysAsyncResetModule extends Module with RequireAsyncReset { + val myAsyncResetReg = RegInit(false.B) // reset is of type AsyncReset +} +``` + +**Note:** This sets the concrete type, but the Scala type will remain `Reset`, so casting may still be necessary. +This comes up most often when using a reset of type `Bool` in logic. + + +### Reset-Agnostic Code + +The purpose of abstract `Reset` is to make it possible to design hardware that is agnostic to the +reset discipline used. +This enables code reuse for utilities and designs where the reset discipline does not matter to +the functionality of the block. + +Consider the two example modules below which are agnostic to the type of reset used within them: + +```scala mdoc:silent +class ResetAgnosticModule extends Module { + val io = IO(new Bundle { + val out = UInt(4.W) + }) + val resetAgnosticReg = RegInit(0.U(4.W)) + resetAgnosticReg := resetAgnosticReg + 1.U + io.out := resetAgnosticReg +} + +class ResetAgnosticRawModule extends RawModule { + val clk = IO(Input(Clock())) + val rst = IO(Input(Reset())) + val out = IO(Output(UInt(8.W))) + + val resetAgnosticReg = withClockAndReset(clk, rst)(RegInit(0.U(8.W))) + resetAgnosticReg := resetAgnosticReg + 1.U + out := resetAgnosticReg +} +``` + +These modules can be used in both synchronous and asynchronous reset domains. +Their reset types will be inferred based on the context within which they are used. + +### Forcing Reset Type + +You can set the type of a Module's implicit reset as described [above](#setting-implicit-reset-type). + +You can also cast to force the concrete type of reset. +* `.asBool` will reinterpret a `Reset` as `Bool` +* `.asAsyncReset` will reinterpret a `Reset` as `AsyncReset`. + +You can then use `withReset` to use a cast reset as the implicit reset. +See ["Multiple Clock Domains"](../explanations/multi-clock) for more information about `withReset`. + + +The following will make `myReg` as well as both `resetAgnosticReg`s synchronously reset: + +```scala mdoc:silent +class ForcedSyncReset extends Module { + // withReset's argument becomes the implicit reset in its scope + withReset (reset.asBool) { + val myReg = RegInit(0.U) + val myModule = Module(new ResetAgnosticModule) + + // RawModules do not have implicit resets so withReset has no effect + val myRawModule = Module(new ResetAgnosticRawModule) + // We must drive the reset port manually + myRawModule.rst := Module.reset // Module.reset grabs the current implicit reset + } +} +``` + +The following will make `myReg` as well as both `resetAgnosticReg`s asynchronously reset: + +```scala mdoc:silent +class ForcedAysncReset extends Module { + // withReset's argument becomes the implicit reset in its scope + withReset (reset.asAsyncReset){ + val myReg = RegInit(0.U) + val myModule = Module(new ResetAgnosticModule) // myModule.reset is connected implicitly + + // RawModules do not have implicit resets so withReset has no effect + val myRawModule = Module(new ResetAgnosticRawModule) + // We must drive the reset port manually + myRawModule.rst := Module.reset // Module.reset grabs the current implicit reset + } +} +``` + +**Note:** such casts (`asBool` and `asAsyncReset`) are not checked by FIRRTL. +In doing such a cast, you as the designer are effectively telling the compiler +that you know what you are doing and to force the type as cast. + +### Last-Connect Semantics + +It is **not** legal to override the reset type using last-connect semantics +unless you are overriding a `DontCare`: + +```scala mdoc:silent +class MyModule extends Module { + val resetBool = Wire(Reset()) + resetBool := DontCare + resetBool := false.B // this is fine + withReset(resetBool) { + val mySubmodule = Module(new Submodule()) + } + resetBool := true.B // this is fine + resetBool := false.B.asAsyncReset // this will error in FIRRTL +} +``` diff --git a/docs/src/explanations/sequential-circuits.md b/docs/src/explanations/sequential-circuits.md new file mode 100644 index 00000000..938416ac --- /dev/null +++ b/docs/src/explanations/sequential-circuits.md @@ -0,0 +1,50 @@ +--- +layout: docs +title: "Sequential Circuits" +section: "chisel3" +--- + +# Sequential Circuits + +```scala mdoc:invisible +import chisel3._ +val in = Bool() +``` +The simplest form of state element supported by Chisel is a positive edge-triggered register, which can be instantiated as: +``` scala mdoc:compile-only +val reg = RegNext(in) +``` +This circuit has an output that is a copy of the input signal `in` delayed by one clock cycle. Note that we do not have to specify the type of Reg as it will be automatically inferred from its input when instantiated in this way. In the current version of Chisel, clock and reset are global signals that are implicitly included where needed. + +Note that registers which do not specify an initial value will not change value upon toggling the reset signal. + +Using registers, we can quickly define a number of useful circuit constructs. For example, a rising-edge detector that takes a boolean signal in and outputs true when the current value is true and the previous value is false is given by: + +```scala mdoc:silent +def risingedge(x: Bool) = x && !RegNext(x) +``` +Counters are an important sequential circuit. To construct an up-counter that counts up to a maximum value, max, then wraps around back to zero (i.e., modulo max+1), we write: +```scala mdoc:silent +def counter(max: UInt) = { + val x = RegInit(0.asUInt(max.getWidth.W)) + x := Mux(x === max, 0.U, x + 1.U) + x +} +``` +The counter register is created in the counter function with a reset value of 0 (with width large enough to hold max), to which the register will be initialized when the global reset for the circuit is asserted. The := assignment to x in counter wires an update combinational circuit which increments the counter value unless it hits the max at which point it wraps back to zero. Note that when x appears on the right-hand side of an assignment, its output is referenced, whereas when on the left-hand side, its input is referenced. +Counters can be used to build a number of useful sequential circuits. For example, we can build a pulse generator by outputting true when a counter reaches zero: +```scala mdoc:silent +// Produce pulse every n cycles. +def pulse(n: UInt) = counter(n - 1.U) === 0.U +``` +A square-wave generator can then be toggled by the pulse train, toggling between true and false on each pulse: +```scala mdoc:silent +// Flip internal state when input true. +def toggle(p: Bool) = { + val x = RegInit(false.B) + x := Mux(p, !x, x) + x +} +// Square wave of a given period. +def squareWave(period: UInt) = toggle(pulse(period >> 1)) +``` diff --git a/docs/src/explanations/supported-hardware.md b/docs/src/explanations/supported-hardware.md new file mode 100644 index 00000000..fe3909e7 --- /dev/null +++ b/docs/src/explanations/supported-hardware.md @@ -0,0 +1,11 @@ +--- +layout: docs +title: "Supported Hardware" +section: "chisel3" +--- + +# Supported Hardware + +While Chisel focuses on binary logic, Chisel can support analog and tri-state wires with the `Analog` type - see [Datatypes in Chisel](data-types). + +We focus on binary logic designs as they constitute the vast majority of designs in practice. Tri-state logic are poorly supported standard industry flows and require special/controlled hard macros in order to be done. diff --git a/docs/src/explanations/unconnected-wires.md b/docs/src/explanations/unconnected-wires.md new file mode 100644 index 00000000..48012d12 --- /dev/null +++ b/docs/src/explanations/unconnected-wires.md @@ -0,0 +1,138 @@ +--- +layout: docs +title: "Unconnected Wires" +section: "chisel3" +--- + +# Unconnected Wires + +The Invalidate API [(#645)](https://github.com/freechipsproject/chisel3/pull/645) adds support to Chisel +for reporting unconnected wires as errors. + +Prior to this pull request, Chisel automatically generated a firrtl `is invalid` for `Module IO()`, and each `Wire()` definition. +This made it difficult to detect cases where output signals were never driven. +Chisel now supports a `DontCare` element, which may be connected to an output signal, indicating that that signal is intentionally not driven. +Unless a signal is driven by hardware or connected to a `DontCare`, Firrtl will complain with a "not fully initialized" error. + +### API + +Output signals may be connected to DontCare, generating a `is invalid` when the corresponding firrtl is emitted. + +```scala mdoc:invisible +import chisel3._ +``` +```scala mdoc:silent + +class Out extends Bundle { + val debug = Bool() + val debugOption = Bool() +} +val io = new Bundle { val out = new Out } +``` + +```scala mdoc:compile-only +io.out.debug := true.B +io.out.debugOption := DontCare +``` + +This indicates that the signal `io.out.debugOption` is intentionally not driven and firrtl should not issue a "not fully initialized" +error for this signal. + +This can be applied to aggregates as well as individual signals: +```scala mdoc:invisible +import chisel3._ +``` +```scala mdoc:silent +import chisel3._ +class ModWithVec extends Module { + // ... + val nElements = 5 + val io = IO(new Bundle { + val outs = Output(Vec(nElements, Bool())) + }) + io.outs <> DontCare + // ... +} + +class TrivialInterface extends Bundle { + val in = Input(Bool()) + val out = Output(Bool()) +} + +class ModWithTrivalInterface extends Module { + // ... + val io = IO(new TrivialInterface) + io <> DontCare + // ... +} +``` + +This feature is controlled by `CompileOptions.explicitInvalidate` and is set to `false` in `NotStrict` (Chisel2 compatibility mode), +and `true` in `Strict` mode. + +You can selectively enable this for Chisel2 compatibility mode by providing your own explicit `compileOptions`, +either for a group of Modules (via inheritance): +```scala mdoc:silent +abstract class ExplicitInvalidateModule extends Module()(chisel3.ExplicitCompileOptions.NotStrict.copy(explicitInvalidate = true)) +``` +or on a per-Module basis: +```scala mdoc:silent +class MyModule extends Module { + override val compileOptions = chisel3.ExplicitCompileOptions.NotStrict.copy(explicitInvalidate = true) + val io = IO(new Bundle { /* ... */ } ) + // ... +} +``` + +Or conversely, disable this stricter checking (which is now the default in pure chisel3): +```scala mdoc:silent +abstract class ImplicitInvalidateModule extends Module()(chisel3.ExplicitCompileOptions.Strict.copy(explicitInvalidate = false)) +``` +or on a per-Module basis: +```scala mdoc:invisible:reset +import chisel3._ +``` +```scala mdoc:silent +class MyModule extends Module { + override val compileOptions = chisel3.ExplicitCompileOptions.Strict.copy(explicitInvalidate = false) + val io = IO(new Bundle { /* ... */ } ) + // ... +} +``` + +Please see the corresponding [API tests](https://github.com/freechipsproject/chisel3/blob/master/src/test/scala/chiselTests/InvalidateAPISpec.scala) +for examples. + +### Determining the unconnected element + +I have an interface with 42 wires. +Which one of them is unconnected? + +The firrtl error message should contain something like: +```bash +firrtl.passes.CheckInitialization$RefNotInitializedException: @[:@6.4] : [module Router] Reference io is not fully initialized. + @[Decoupled.scala 38:19:@48.12] : node _GEN_23 = mux(and(UInt<1>("h1"), eq(UInt<2>("h3"), _T_84)), _GEN_2, VOID) @[Decoupled.scala 38:19:@48.12] + @[Router.scala 78:30:@44.10] : node _GEN_36 = mux(_GEN_0.ready, _GEN_23, VOID) @[Router.scala 78:30:@44.10] + @[Router.scala 75:26:@39.8] : node _GEN_54 = mux(io.in.valid, _GEN_36, VOID) @[Router.scala 75:26:@39.8] + @[Router.scala 70:50:@27.6] : node _GEN_76 = mux(io.load_routing_table_request.valid, VOID, _GEN_54) @[Router.scala 70:50:@27.6] + @[Router.scala 65:85:@19.4] : node _GEN_102 = mux(_T_62, VOID, _GEN_76) @[Router.scala 65:85:@19.4] + : io.outs[3].bits.body <= _GEN_102 +``` +The first line is the initial error report. +Successive lines, indented and beginning with source line information indicate connections involving the problematic signal. +Unfortunately, if these are `when` conditions involving muxes, they may be difficult to decipher. +The last line of the group, indented and beginning with a `:` should indicate the uninitialized signal component. +This example (from the [Router tutorial](https://github.com/ucb-bar/chisel-tutorial/blob/release/src/main/scala/examples/Router.scala)) +was produced when the output queue bits were not initialized. +The old code was: +```scala + io.outs.foreach { out => out.noenq() } +``` +which initialized the queue's `valid` bit, but did not initialize the actual output values. +The fix was: +```scala + io.outs.foreach { out => + out.bits := 0.U.asTypeOf(out.bits) + out.noenq() + } +``` diff --git a/docs/src/explanations/width-inference.md b/docs/src/explanations/width-inference.md new file mode 100644 index 00000000..66d9736d --- /dev/null +++ b/docs/src/explanations/width-inference.md @@ -0,0 +1,40 @@ +--- +layout: docs +title: "Width Inference" +section: "chisel3" +--- + +# Width Inference + +Chisel provides bit width inference to reduce design effort. Users are encouraged to manually specify widths of ports and registers to prevent any surprises, but otherwise unspecified widths will be inferred by the Firrtl compiler. + +For all circuit components declared with unspecified widths, the FIRRTL compiler will infer the minimum possible width that maintains the legality of all its incoming connections. Implicit here is that inference is done in a right to left fashion in the sense of an assignment statement in chisel, i.e. from the left hand side from the right hand side. If a component has no incoming connections, and the width is unspecified, then an error is thrown to indicate that the width could not be inferred. + +For module input ports with unspecified widths, the inferred width is the minimum possible width that maintains the legality of all incoming connections to all instantiations of the module. +The width of a ground-typed multiplexor expression is the maximum of its two corresponding input widths. For multiplexing aggregate-typed expressions, the resulting widths of each leaf subelement is the maximum of its corresponding two input leaf subelement widths. +The width of a conditionally valid expression is the width of its input expression. For the full formal description see the [Firrtl Spec](https://github.com/freechipsproject/firrtl/blob/master/spec/spec.pdf). + +Hardware operators have output widths as defined by the following set of rules: + +| operation | bit width | +| --------- | --------- | +| `z = x + y` *or* `z = x +% y` | `w(z) = max(w(x), w(y))` | +| `z = x +& y` | `w(z) = max(w(x), w(y)) + 1` | +| `z = x - y` *or* `z = x -% y` | `w(z) = max(w(x), w(y))` | +| `z = x -& y` | `w(z) = max(w(x), w(y)) + 1` | +| `z = x & y` | `w(z) = max(w(x), w(y))` | +| `z = Mux(c, x, y)` | `w(z) = max(w(x), w(y))` | +| `z = w * y` | `w(z) = w(x) + w(y)` | +| `z = x << n` | `w(z) = w(x) + maxNum(n)` | +| `z = x >> n` | `w(z) = w(x) - minNum(n)` | +| `z = Cat(x, y)` | `w(z) = w(x) + w(y)` | +| `z = Fill(n, x)` | `w(z) = w(x) * maxNum(n)` | + +>where for instance `w(z)` is the bit width of wire `z`, and the `&` +rule applies to all bitwise logical operations. + +Given a path of connections that begins with an unspecified width element (most commonly a top-level input), then the compiler will throw an exception indicating a certain width was uninferrable. + +A common "gotcha" comes from truncating addition and subtraction with the operators `+` and `-`. Users who want the result to maintain the full, expanded precision of the addition or subtraction should use the expanding operators `+&` and `-&`. + +> The default truncating operation comes from Chisel's history as a microprocessor design language. diff --git a/docs/src/introduction.md b/docs/src/introduction.md new file mode 100644 index 00000000..3b68aae2 --- /dev/null +++ b/docs/src/introduction.md @@ -0,0 +1,41 @@ +--- +layout: docs +title: "Introduction" +section: "chisel3" +--- + +# An Introduction to Chisel + +_Chisel_ (Constructing +Hardware In a Scala Embedded Language) is a hardware +construction language embedded in the high-level programming language +Scala. + Chisel is a library of special class +definitions, predefined objects, and usage conventions within [Scala](https://www.scala-lang.org/), +so when you write Chisel you are actually writing a Scala +program that constructs a hardware graph. +As you gain experience and want to make your code simpler or more +reusable, you will find it important to leverage the underlying power +of the Scala language. We recommend you consult one of the excellent +Scala books to become more expert in Scala programming. + +For a tutorial covering both Chisel and Scala, see the +[**online Chisel Bootcamp**](https://mybinder.org/v2/gh/freechipsproject/chisel-bootcamp/master). + +For quick reference "How-To" guides see the [Cookbooks](cookbooks/cookbooks). + +For a deeper introduction to key concepts in Chisel see the [Explanations](explanations/explanations). + +The [API Documentation](https://www.chisel-lang.org/api/) gives the detailed reference for the Chisel source code. +Note that previous versions can be found via the sidebar menu at [https://www.chisel-lang.org/chisel3]. + +The [Resources](resources/resources) provides links to other useful resources for learning and working with Chisel. + +The [Appendix](appendix/appendix) covers some more advanced topics. + +The [Developers](developers/developers) section provides information for those working on the Chisel library itself. + +>Throughout these pages, we format commentary on our design choices as in +this paragraph. You should be able to skip the commentary sections +and still fully understand how to use Chisel, but we hope you'll find +them interesting. diff --git a/docs/src/resources/faqs.md b/docs/src/resources/faqs.md new file mode 100644 index 00000000..debdfcbe --- /dev/null +++ b/docs/src/resources/faqs.md @@ -0,0 +1,284 @@ +--- +layout: docs +title: "Frequently Asked Questions" +section: "chisel3" +--- + +# Frequently Asked Questions + +* [Where should I start if I want to learn Chisel?](#where-should-i-start-if-i-want-to-learn-chisel) +* [How do I ... in Chisel?](#how-do-i-do--eg-like-that-in-verilog-in-chisel) +* [How can I contribute to Chisel?](#how-can-i-contribute-to-chisel) +* [What is the difference between release and master branches?](#what-is-the-difference-between-release-and-master-branches) +* [Why DecoupledIO instead of ReadyValidIO?](#why-decoupledio-instead-of-readyvalidio) +* [Why do I have to wrap module instantiations in `Module(...)`?](#why-do-i-have-to-wrap-module-instantiations-in-module) +* [Why Chisel?](#why-chisel) +* [Does Chisel support X and Z logic values?](#does-chisel-support-x-and-z-logic-values) +* [I just want some Verilog; what do I do?](#get-me-verilog) +* [I just want some FIRRTL; what do I do?](#get-me-firrtl) +* [Why doesn't Chisel tell me which wires aren't connected?](#why-doesnt-chisel-tell-me-which-wires-arent-connected) +* [What does `Reference ... is not fully initialized.` mean?](#what-does-reference--is-not-fully-initialized-mean) +* [Can I specify behavior before and after generated initial blocks?](#can-i-specify-behavior-before-and-after-generated-initial-blocks) + +### Where should I start if I want to learn Chisel? + +We recommend the [Chisel Bootcamp](https://github.com/freechipsproject/chisel-bootcamp) for getting started with Chisel. + +### How do I do ... (e.g. like that in Verilog) in Chisel? + +See the [cookbooks](../cookbooks/cookbook). + +### How can I contribute to Chisel? + +A good to place to start is to fill out the [How Can I Contribute Form](https://docs.google.com/forms/d/e/1FAIpQLSfwTTY8GkfSZ2sU2T2mNpfNMpIM70GlXOrjqiHoC9ZBvwn_CA/viewform). + +### What is the difference between release and master branches? + +We have two main branches for each main Chisel project: + +- `master` +- `release` + +`master` is the main development branch and it is updated frequently (often several times a day). +Although we endeavour to keep the `master` branches in sync, they may drift out of sync for a day or two. +We do not publish the `master` branches. +If you wish to use them, you need to clone the GitHub repositories and use `sbt publishLocal` to make them available on your local machine. + +The `release` branches are updated less often (currently bi-weekly) and we try to guarantee they are in sync. +We publish these to Sonatype/Maven on a bi-weekly basis. + +In general, you can not mix `release` and `master` branches and assume they will work. + +The default branches for the user-facing repositories (chisel-template and chisel-tutorial) are the `release` branches - these should always *just work* for new users as they use the `release` branches of chisel projects. + +If you want to use something more current than the `release` branch, you should `git checkout master` for all the chisel repos you intend to use, then `sbt publishLocal` them in this order: + +- firrtl +- firrtl-interpreter +- chisel3 +- chisel-testers + +Then, if you're working with the user-facing repositories: + +- chisel-tutorial +- chisel-template + +Since this is a substantial amount of work (with no guarantee of success), unless you are actively involved in Chisel development, we encourage you to stick with the `release` branches and their respective dependencies. + +### Why DecoupledIO instead of ReadyValidIO? + +There are multiple kinds of Ready/Valid interfaces that impose varying restrictions on the producers and consumers. Chisel currently provides the following: + +* [DecoupledIO](https://chisel.eecs.berkeley.edu/api/index.html#chisel3.util.DecoupledIO) - No guarantees +* [IrrevocableIO](https://chisel.eecs.berkeley.edu/api/index.html#chisel3.util.IrrevocableIO) - Producer promises to not change the value of 'bits' after a cycle where 'valid' is high and 'ready' is low. Additionally, once 'valid' is raised it will never be lowered until after 'ready' has also been raised. + +### Why do I have to wrap module instantiations in `Module(...)`? + +In short: Limitations of Scala + +Chisel Modules are written by defining a [Scala class](http://docs.scala-lang.org/tutorials/tour/classes.html) and implementing its constructor. As elaboration runs, Chisel constructs a hardware AST from these Modules. The compiler needs hooks to run before and after the actual construction of the Module object. In Scala, superclasses are fully initialized before subclasses, so by extending Module, Chisel has the ability to run some initialization code before the user's Module is constructed. However, there is no such hook to run after the Module object is initialized. By wrapping Module instantiations in the Module object's apply method (ie. `Module(...)`), Chisel is able to perform post-initialization actions. There is a [proposed solution](https://issues.scala-lang.org/browse/SI-4330), so eventually this requirement will be lifted, but for now, wrap those Modules! + +### Why Chisel? + +Borrowed from [Chisel Motivation](../explanations/motivation) + +>We were motivated to develop a new hardware language by years of +struggle with existing hardware description languages in our research +projects and hardware design courses. _Verilog_ and _VHDL_ were developed +as hardware _simulation_ languages, and only later did they become +a basis for hardware _synthesis_. Much of the semantics of these +languages are not appropriate for hardware synthesis and, in fact, +many constructs are simply not synthesizable. Other constructs are +non-intuitive in how they map to hardware implementations, or their +use can accidently lead to highly inefficient hardware structures. +While it is possible to use a subset of these languages and still get +acceptable results, they nonetheless present a cluttered and confusing +specification model, particularly in an instructional setting. + +>However, our strongest motivation for developing a new hardware +language is our desire to change the way that electronic system design +takes place. We believe that it is important to not only teach +students how to design circuits, but also to teach them how to design +*circuit generators* ---programs that automatically generate +designs from a high-level set of design parameters and constraints. +Through circuit generators, we hope to leverage the hard work of +design experts and raise the level of design abstraction for everyone. +To express flexible and scalable circuit construction, circuit +generators must employ sophisticated programming techniques to make +decisions concerning how to best customize their output circuits +according to high-level parameter values and constraints. While +Verilog and VHDL include some primitive constructs for programmatic +circuit generation, they lack the powerful facilities present in +modern programming languages, such as object-oriented programming, +type inference, support for functional programming, and reflection. + +>Instead of building a new hardware design language from scratch, we +chose to embed hardware construction primitives within an existing +language. We picked Scala not only because it includes the +programming features we feel are important for building circuit +generators, but because it was specifically developed as a base for +domain-specific languages. + +### Does Chisel support X and Z logic values + +Chisel does not directly support Verilog logic values ```x``` *unknown* and ```z``` *high-impedance*. There are a number of reasons to want to avoid these values. See:[The Dangers of Living With An X](http://infocenter.arm.com/help/topic/com.arm.doc.arp0009a/Verilog_X_Bugs.pdf) and [Malicious LUT: A stealthy FPGA Trojan injected and triggered by the design flow](http://ieeexplore.ieee.org/document/7827620/). Chisel has it's own eco-system of unit and functional testers that limit the need for ```x``` and ```z``` and their omission simplify language implementation, design, and testing. The circuits created by chisel do not preclude developers from using ```x``` and ```z``` in downstream toolchains as they see fit. + +### Get me Verilog +I wrote a module and I want to see the Verilog; what do I do? + +Here's a simple hello world module in a file HelloWorld.scala. + + +```scala +package intro +``` +```scala mdoc:silent +import chisel3._ +class HelloWorld extends Module { + val io = IO(new Bundle{}) + printf("hello world\n") +} +``` + +Add the following +```scala mdoc:silent +import chisel3.stage.ChiselStage +object VerilogMain extends App { + (new ChiselStage).emitVerilog(new HelloWorld) +} +``` +Now you can get some Verilog. Start sbt: +``` +bash> sbt +> run-main intro.VerilogMain +[info] Running intro.VerilogMain +[info] [0.004] Elaborating design... +[info] [0.100] Done elaborating. +[success] Total time: 1 s, completed Jan 12, 2017 6:24:03 PM +``` +or as a one-liner: +``` +bash> sbt 'runMain intro.VerilogMain' +``` +After either of the above there will be a HelloWorld.v file in the current directory: +```scala mdoc:invisible +val verilog = ChiselStage.emitVerilog(new HelloWorld) +``` +```scala mdoc:passthrough +println("```verilog") +println(verilog) +println("```") +``` + +You can see additional options with +``` +bash> sbt 'runMain intro.HelloWorld --help' +``` +This will return a comprehensive usage line with available options. + +For example to place the output in a directory name buildstuff use +``` +bash> sbt 'runMain intro.HelloWorld --target-dir buildstuff --top-name HelloWorld' +``` + +Alternatively, you can also use the sbt console to invoke the Verilog driver: + +``` +$ sbt +> console +[info] Starting scala interpreter... +Welcome to Scala 2.12.13 (OpenJDK 64-Bit Server VM, Java 1.8.0_275). +Type in expressions for evaluation. Or try :help. + +scala> (new chisel3.stage.ChiselStage).emitVerilog(new HelloWorld()) +chisel3.Driver.execute(Array[String](), () => new HelloWorld) +Elaborating design... +Done elaborating. +res1: String = +"module HelloWorld( + input clock, + input reset +); +... +``` + +As before, there should be a HelloWorld.v file in the current directory. + +Note: Using the following, without the `new`, +will ONLY return the string representation, and will not emit a `.v` file: + +```scala mdoc:silent +ChiselStage.emitVerilog(new HelloWorld()) +``` + +### Get me FIRRTL + +If for some reason you don't want the Verilog (e.g. maybe you want to run some custom transformations before exporting to Verilog), then use something along these lines (replace Multiplier with your module): + +```scala +package intro +``` +```scala mdoc:silent:reset + +import chisel3._ +import chisel3.stage.ChiselStage + +class MyFirrtlModule extends Module { + val io = IO(new Bundle{}) +} + +object FirrtlMain extends App { + (new ChiselStage).emitFirrtl(new MyFirrtlModule) +} +``` + +Run it with: + +``` +sbt 'runMain intro.FirrtlMain' +``` +```scala mdoc:invisible +val theFirrtl = ChiselStage.emitFirrtl(new MyFirrtlModule) +``` +```scala mdoc:passthrough +println("```") +println(theFirrtl) +println("```") +``` + +Alternatively, you can also use the sbt console to invoke the FIRRTL driver directly (replace MyFirrtlModule with your module name): + +``` +$ sbt +> console +[info] Starting scala interpreter... +Welcome to Scala 2.12.13 (OpenJDK 64-Bit Server VM, Java 1.8.0_275). +Type in expressions for evaluation. Or try :help. + +scala> (new chisel3.stage.ChiselStage).emitFirrtl(new MyFirrtlModule) +Elaborating design... +Done elaborating. +res3: String = ... +``` + +### Why doesn't Chisel tell me which wires aren't connected? + +As of commit [c313e13](https://github.com/freechipsproject/chisel3/commit/c313e137d4e562ef20195312501840ceab8cbc6a) it can! +Read more at [Unconnected Wires](../explanations/unconnected-wires) for details. + +### What does `Reference ... is not fully initialized.` mean? + +It means that you have unconnected wires in your design which could be an indication of a design bug. + +In Chisel2 compatibility mode (`NotStrict` compile options), chisel generates firrtl code that disables firrtl's initialized wire checks. +In pure chisel3 (`Strict` compile options), the generated firrtl code does not contain these disablers (`is invalid`). +Output wires that are not driven (not connected) are reported by firrtl as `not fully initialized`. +Read more at [Unconnected Wires](../explanations/unconnected-wires) for details on solving the problem. + +### Can I specify behavior before and after generated initial blocks? +Users may define the following macros if they wish to specify behavior before or after emitted initial blocks. + +* `BEFORE_INITIAL`, which is called before the emitted (non-empty) initial block if it is defined +* `AFTER_INITIAL`, which is called after the emitted (non-empty) initial block if it is defined + +These macros may be useful for turning coverage on and off. diff --git a/docs/src/resources/resources.md b/docs/src/resources/resources.md new file mode 100644 index 00000000..fadd26a1 --- /dev/null +++ b/docs/src/resources/resources.md @@ -0,0 +1,17 @@ +--- +layout: docs +title: "Resources and References" +section: "chisel3" +--- + +# Chisel Resources + +The *best resource* to learn about Chisel is the [**online Chisel Bootcamp**](https://mybinder.org/v2/gh/freechipsproject/chisel-bootcamp/master). This runs in your browser and assumes no prior Scala knowledge. (You may also run this locally via the [backing chisel-bootcamp GitHub repository](https://github.com/freechipsproject/chisel-bootcamp).) + +When you're ready to build your own circuits in Chisel, **we recommend starting from the [Chisel Template](https://github.com/freechipsproject/chisel-template) repository**, which provides a pre-configured project, example design, and testbench. Follow the [chisel-template readme](https://github.com/freechipsproject/chisel-template) to get started. + +The following additional resources and references may be useful: + +- [Chisel Cheatsheet](https://github.com/freechipsproject/chisel-cheatsheet/releases/latest/download/chisel_cheatsheet.pdf) +- [Digital Design With Chisel](https://github.com/schoeberl/chisel-book) +- [Frequently Asked Questions](faqs) diff --git a/docs/src/wiki-deprecated/combinational-circuits.md b/docs/src/wiki-deprecated/combinational-circuits.md deleted file mode 100644 index 813549c9..00000000 --- a/docs/src/wiki-deprecated/combinational-circuits.md +++ /dev/null @@ -1,81 +0,0 @@ ---- -layout: docs -title: "Combinational Circuits" -section: "chisel3" ---- -A circuit is represented as a graph of nodes in Chisel. Each node is -a hardware operator that has zero or more inputs and that drives one -output. A literal, introduced above, is a degenerate kind of node -that has no inputs and drives a constant value on its output. One way -to create and wire together nodes is using textual expressions. For -example, we can express a simple combinational logic circuit -using the following expression: - -```scala -(a & b) | (~c & d) -``` - -The syntax should look familiar, with `&` and `|` -representing bitwise-AND and -OR respectively, and `~` -representing bitwise-NOT. The names `a` through `d` -represent named wires of some (unspecified) width. - -Any simple expression can be converted directly into a circuit tree, -with named wires at the leaves and operators forming the internal -nodes. The final circuit output of the expression is taken from the -operator at the root of the tree, in this example, the bitwise-OR. - -Simple expressions can build circuits in the shape of trees, but to -construct circuits in the shape of arbitrary directed acyclic graphs -(DAGs), we need to describe fan-out. In Chisel, we do this by naming -a wire that holds a subexpression that we can then reference multiple -times in subsequent expressions. We name a wire in Chisel by -declaring a variable. For example, consider the select expression, -which is used twice in the following multiplexer description: -```scala -val sel = a | b -val out = (sel & in1) | (~sel & in0) -``` - -The keyword `val` is part of Scala, and is used to name variables -that have values that won't change. It is used here to name the -Chisel wire, `sel`, holding the output of the first bitwise-OR -operator so that the output can be used multiple times in the second -expression. - -### Wires - -Chisel also supports wires as hardware nodes to which one can assign values or connect other nodes. - -```scala -val myNode = Wire(UInt(8.W)) -when (isReady) { - myNode := 255.U -} .otherwise { - myNode := 0.U -} -``` - -```scala -val myNode = Wire(UInt(8.W)) -when (input > 128.U) { - myNode := 255.U -} .elsewhen (input > 64.U) { - myNode := 1.U -} .otherwise { - myNode := 0.U -} -``` - -Note that the last connection to a Wire takes effect. For example, the following two Chisel circuits are equivalent: - -```scala -val myNode = Wire(UInt(8.W)) -myNode := 10.U -myNode := 0.U -``` - -```scala -val myNode = Wire(UInt(8.W)) -myNode := 0.U -``` diff --git a/docs/src/wiki-deprecated/cookbook.md b/docs/src/wiki-deprecated/cookbook.md deleted file mode 100644 index 9a10a689..00000000 --- a/docs/src/wiki-deprecated/cookbook.md +++ /dev/null @@ -1,470 +0,0 @@ ---- -layout: docs -title: "Cookbook" -section: "chisel3" ---- - -Welcome to the Chisel cookbook. This cookbook is still in early stages. If you have any requests or examples to share, please [file an issue](https://github.com/ucb-bar/chisel3/issues/new) and let us know! - -Please note that these examples make use of [Chisel's scala-style printing](printing#scala-style). - -* Converting Chisel Types to/from UInt - * [How do I create a UInt from an instance of a Bundle?](#how-do-i-create-a-uint-from-an-instance-of-a-bundle) - * [How do I create a Bundle from a UInt?](#how-do-i-create-a-bundle-from-a-uint) - * [How do I create a Vec of Bools from a UInt?](#how-do-i-create-a-vec-of-bools-from-a-uint) - * [How do I create a UInt from a Vec of Bool?](#how-do-i-create-a-uint-from-a-vec-of-bool) -* Vectors and Registers - * [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 create a finite state machine?](#how-do-i-create-a-finite-state-machine-fsm) -* [How do I unpack a value ("reverse concatenation") like in Verilog?](#how-do-i-unpack-a-value-reverse-concatenation-like-in-verilog) -* [How do I do subword assignment (assign to some bits in a UInt)?](#how-do-i-do-subword-assignment-assign-to-some-bits-in-a-uint) -* [How do I create an optional I/O?](#how-do-i-create-an-optional-io) -* Predictable Naming - * [How do I get Chisel to name signals properly in blocks like when/withClockAndReset?](#how-do-i-get-chisel-to-name-signals-properly-in-blocks-like-whenwithclockandreset) - * [How do I get Chisel to name the results of vector reads properly?](#how-do-i-get-chisel-to-name-the-results-of-vector-reads-properly) - * [How can I dynamically set/parametrize the name of a module?](#how-can-i-dynamically-setparametrize-the-name-of-a-module) - -## Converting Chisel Types to/from UInt - -### How do I create a UInt from an instance of a Bundle? - -Call [`asUInt`](https://www.chisel-lang.org/api/latest/chisel3/Bundle.html#asUInt():chisel3.UInt) on the [`Bundle`](https://www.chisel-lang.org/api/latest/chisel3/Bundle.html) instance. - -```scala mdoc:silent:reset -import chisel3._ - -class MyBundle extends Bundle { - val foo = UInt(4.W) - val bar = UInt(4.W) -} - -class Foo extends RawModule { - val bundle = Wire(new MyBundle) - bundle.foo := 0xc.U - bundle.bar := 0x3.U - val uint = bundle.asUInt -} -``` - -### How do I create a Bundle from a UInt? - -Use the [`asTypeOf`](https://www.chisel-lang.org/api/latest/chisel3/UInt.html#asTypeOf[T%3C:chisel3.Data](that:T):T) method to reinterpret the [`UInt`](https://www.chisel-lang.org/api/latest/chisel3/UInt.html) as the type of the [`Bundle`](https://www.chisel-lang.org/api/latest/chisel3/Bundle.html). - -```scala mdoc:silent:reset -import chisel3._ - -class MyBundle extends Bundle { - val foo = UInt(4.W) - val bar = UInt(4.W) -} - -class Foo extends RawModule { - val uint = 0xb4.U - val bundle = uint.asTypeOf(new MyBundle) -} -``` - -### How do I create a Vec of Bools from a UInt? - -Use [`VecInit`](https://www.chisel-lang.org/api/latest/chisel3/VecInit$.html) given a `Seq[Bool]` generated using the [`asBools`](https://www.chisel-lang.org/api/latest/chisel3/UInt.html#asBools():Seq[chisel3.Bool]) method. - -```scala mdoc:silent:reset -import chisel3._ - -class Foo extends RawModule { - val uint = 0xc.U - val vec = VecInit(uint.asBools) -} -``` - -### How do I create a UInt from a Vec of Bool? - -Use the builtin function [`asUInt`](https://www.chisel-lang.org/api/latest/chisel3/Vec.html#asUInt():chisel3.UInt) - -```scala mdoc:silent:reset -import chisel3._ - -class Foo extends RawModule { - val vec = VecInit(true.B, false.B, true.B, true.B) - val uint = vec.asUInt -} -``` - -## Vectors and Registers - -### How do I create a Vector of Registers? - -**Rule! Use Reg of Vec not Vec of Reg!** - -You create a [Reg of type Vec](#how-do-i-create-a-reg-of-type-vec). Because Vecs are a *type* (like `UInt`, `Bool`) rather than a *value*, we must bind the Vec to some concrete *value*. - -### How do I create a Reg of type Vec? - -For more information, the API Documentation for [`Vec`](https://www.chisel-lang.org/api/latest/chisel3/Vec.html) provides more information. - -```scala mdoc:silent:reset -import chisel3._ - -class Foo extends RawModule { - val regOfVec = Reg(Vec(4, UInt(32.W))) // Register of 32-bit UInts - regOfVec(0) := 123.U // Assignments to elements of the Vec - regOfVec(1) := 456.U - regOfVec(2) := 789.U - regOfVec(3) := regOfVec(0) - - // Reg of Vec of 32-bit UInts initialized to zero - // Note that Seq.fill constructs 4 32-bit UInt literals with the value 0 - // VecInit(...) then constructs a Wire of these literals - // The Reg is then initialized to the value of the Wire (which gives it the same type) - val initRegOfVec = RegInit(VecInit(Seq.fill(4)(0.U(32.W)))) -} -``` - -### How do I create a finite state machine (FSM)? - -The advised way is to use [`ChiselEnum`](https://www.chisel-lang.org/api/latest/chisel3/experimental/index.html#ChiselEnum=chisel3.experimental.EnumFactory) to construct enumerated types representing the state of the FSM. -State transitions are then handled with [`switch`](https://www.chisel-lang.org/api/latest/chisel3/util/switch$.html)/[`is`](https://www.chisel-lang.org/api/latest/chisel3/util/is$.html) and [`when`](https://www.chisel-lang.org/api/latest/chisel3/when$.html)/[`.elsewhen`](https://www.chisel-lang.org/api/latest/chisel3/WhenContext.html#elsewhen(elseCond:=%3Echisel3.Bool)(block:=%3EUnit)(implicitsourceInfo:chisel3.internal.sourceinfo.SourceInfo,implicitcompileOptions:chisel3.CompileOptions):chisel3.WhenContext)/[`.otherwise`](https://www.chisel-lang.org/api/latest/chisel3/WhenContext.html#otherwise(block:=%3EUnit)(implicitsourceInfo:chisel3.internal.sourceinfo.SourceInfo,implicitcompileOptions:chisel3.CompileOptions):Unit). - -```scala mdoc:silent:reset -import chisel3._ -import chisel3.util.{switch, is} -import chisel3.experimental.ChiselEnum - -object DetectTwoOnes { - object State extends ChiselEnum { - val sNone, sOne1, sTwo1s = Value - } -} - -/* This FSM detects two 1's one after the other */ -class DetectTwoOnes extends Module { - import DetectTwoOnes.State - import DetectTwoOnes.State._ - - val io = IO(new Bundle { - val in = Input(Bool()) - val out = Output(Bool()) - val state = Output(State()) - }) - - val state = RegInit(sNone) - - io.out := (state === sTwo1s) - io.state := state - - switch (state) { - is (sNone) { - when (io.in) { - state := sOne1 - } - } - is (sOne1) { - when (io.in) { - state := sTwo1s - } .otherwise { - state := sNone - } - } - is (sTwo1s) { - when (!io.in) { - state := sNone - } - } - } -} -``` - -Note: the `is` statement can take multiple conditions e.g. `is (sTwo1s, sOne1) { ... }`. - -### How do I unpack a value ("reverse concatenation") like in Verilog? - -In Verilog, you can do something like the following which will unpack a the value `z`: - -```verilog -wire [1:0] a; -wire [3:0] b; -wire [2:0] c; -wire [8:0] z = [...]; -assign {a,b,c} = z; -``` - -Unpacking often corresponds to reinterpreting an unstructured data type as a structured data type. -Frequently, this structured type is used prolifically in the design, and has been declared as in the following example: - -```scala mdoc:silent:reset -import chisel3._ - -class MyBundle extends Bundle { - val a = UInt(2.W) - val b = UInt(4.W) - val c = UInt(3.W) -} -``` - -The easiest way to accomplish this in Chisel would be: - -```scala mdoc:silent -class Foo extends RawModule { - val z = Wire(UInt(9.W)) - z := DontCare // This is a dummy connection - val unpacked = z.asTypeOf(new MyBundle) - printf("%d", unpacked.a) - printf("%d", unpacked.b) - printf("%d", unpacked.c) -} -``` - -If you **really** need to do this for a one-off case (Think thrice! It is likely you can better structure the code using bundles), then rocket-chip has a [Split utility](https://github.com/freechipsproject/rocket-chip/blob/723af5e6b69e07b5f94c46269a208a8d65e9d73b/src/main/scala/util/Misc.scala#L140) which can accomplish this. - -### How do I do subword assignment (assign to some bits in a UInt)? - -You may try to do something like the following where you want to assign only some bits of a Chisel type. -Below, the left-hand side connection to `io.out(0)` is not allowed. - -```scala mdoc:silent:reset -import chisel3._ -import chisel3.stage.{ChiselStage, ChiselGeneratorAnnotation} - -class Foo extends Module { - val io = IO(new Bundle { - val bit = Input(Bool()) - val out = Output(UInt(10.W)) - }) - io.out(0) := io.bit -} -``` - -If you try to compile this, you will get an error. -```scala mdoc:crash -(new ChiselStage).execute(Array("-X", "verilog"), Seq(new ChiselGeneratorAnnotation(() => new Foo))) -``` - -Chisel3 *does not support subword assignment*. -The reason for this is that subword assignment generally hints at a better abstraction with an aggregate/structured types, i.e., a `Bundle` or a `Vec`. - -If you must express it this way, one approach is to blast your `UInt` to a `Vec` of `Bool` and back: - -```scala mdoc:silent:reset -import chisel3._ - -class Foo extends Module { - val io = IO(new Bundle { - val in = Input(UInt(10.W)) - val bit = Input(Bool()) - val out = Output(UInt(10.W)) - }) - val bools = VecInit(io.in.asBools) - bools(0) := io.bit - io.out := bools.asUInt -} -``` - - -### How do I create an optional I/O? - -The following example is a module which includes the optional port `out2` only if the given parameter is `true`. - -```scala mdoc:silent:reset -import chisel3._ - -class ModuleWithOptionalIOs(flag: Boolean) extends Module { - val io = IO(new Bundle { - val in = Input(UInt(12.W)) - val out = Output(UInt(12.W)) - val out2 = if (flag) Some(Output(UInt(12.W))) else None - }) - - io.out := io.in - if (flag) { - io.out2.get := io.in - } -} -``` - -The following is an example where an entire `IO` is optional: - -```scala mdoc:silent:reset -import chisel3._ - -class ModuleWithOptionalIO(flag: Boolean) extends Module { - val in = if (flag) Some(IO(Input(Bool()))) else None - val out = IO(Output(Bool())) - - out := in.getOrElse(false.B) -} -``` - -## Predictable Naming - -### How do I get Chisel to name signals properly in blocks like when/withClockAndReset? - -To get Chisel to name signals (wires and registers) declared inside of blocks like `when`, `withClockAndReset`, etc, use the [`@chiselName`](https://www.chisel-lang.org/api/latest/chisel3/experimental/package$$chiselName.html) annotation as shown below: - -```scala mdoc:silent:reset -import chisel3._ -import chisel3.experimental.chiselName - -@chiselName -class TestMod extends Module { - val io = IO(new Bundle { - val a = Input(Bool()) - val b = Output(UInt(4.W)) - }) - when (io.a) { - val innerReg = RegInit(5.U(4.W)) - innerReg := innerReg + 1.U - io.b := innerReg - } .otherwise { - io.b := 10.U - } -} -``` - -Note that you will need to add the following line to your project's `build.sbt` file. - -```scala -addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full) -``` - -If we compile this module *without* `@chiselName`, Chisel is not able to name `innerReg` correctly (notice the `_T`): - -```scala mdoc:passthrough -import chisel3.stage.{ChiselStage, ChiselGeneratorAnnotation} -import firrtl.annotations.DeletedAnnotation -import firrtl.EmittedVerilogCircuitAnnotation - -class TestModWithout extends Module { - override val desiredName = "TestMod" - val io = IO(new Bundle { - val a = Input(Bool()) - val b = Output(UInt(4.W)) - }) - when (io.a) { - val innerReg = RegInit(5.U(4.W)) - innerReg := innerReg + 1.U - io.b := innerReg - } .otherwise { - io.b := 10.U - } -} - -(new ChiselStage) - .execute(Array("-X", "verilog"), Seq(ChiselGeneratorAnnotation(() => new TestModWithout))) - .collectFirst{ case DeletedAnnotation(_, a: EmittedVerilogCircuitAnnotation) => a.value.value } - .foreach(a => println(s"""|```verilog - |$a - |```""".stripMargin)) -``` - -However, if we use `@chiselName` then the register previously called `_T` is now `innerReg`: -```scala mdoc:passthrough -(new ChiselStage) - .execute(Array("-X", "verilog"), Seq(ChiselGeneratorAnnotation(() => new TestMod))) - .collectFirst{ case DeletedAnnotation(_, a: EmittedVerilogCircuitAnnotation) => a.value.value } - .foreach(a => println(s"""|```verilog - |$a - |```""".stripMargin)) -``` -### How do I get Chisel to name the results of vector reads properly? -Currently, name information is lost when using dynamic indexing. For example: -```scala -class Foo extends Module { - val io = IO(new Bundle { - val in = Input(Vec(4, Bool())) - val idx = Input(UInt(2.W)) - val en = Input(Bool()) - val out = Output(Bool()) - }) - - val x = io.in(io.idx) - val y = x && io.en - io.out := y -} -``` - -The above code loses the `x` name, instead using `_GEN_3` (the other `_GEN_*` signals are expected). -```verilog -module Foo( - input clock, - input reset, - input io_in_0, - input io_in_1, - input io_in_2, - input io_in_3, - input [1:0] io_idx, - input io_en, - output io_out -); - wire _GEN_1; // @[main.scala 15:13] - wire _GEN_2; // @[main.scala 15:13] - wire _GEN_3; // @[main.scala 15:13] - assign _GEN_1 = 2'h1 == io_idx ? io_in_1 : io_in_0; // @[main.scala 15:13] - assign _GEN_2 = 2'h2 == io_idx ? io_in_2 : _GEN_1; // @[main.scala 15:13] - assign _GEN_3 = 2'h3 == io_idx ? io_in_3 : _GEN_2; // @[main.scala 15:13] - assign io_out = _GEN_3 & io_en; // @[main.scala 16:10] -endmodule -``` - -This can be worked around by creating a wire and connecting the dynamic index to the wire: -```scala -val x = WireInit(io.in(io.idx)) -``` - -Which produces: -```verilog -module Foo( - input clock, - input reset, - input io_in_0, - input io_in_1, - input io_in_2, - input io_in_3, - input [1:0] io_idx, - input io_en, - output io_out -); - wire _GEN_1; - wire _GEN_2; - wire x; - assign _GEN_1 = 2'h1 == io_idx ? io_in_1 : io_in_0; - assign _GEN_2 = 2'h2 == io_idx ? io_in_2 : _GEN_1; - assign x = 2'h3 == io_idx ? io_in_3 : _GEN_2; - assign io_out = x & io_en; // @[main.scala 16:10] -endmodule -``` -### How can I dynamically set/parametrize the name of a module? - -You can override the `desiredName` function. This works with normal Chisel modules and `BlackBox`es. Example: - -```scala mdoc:silent:reset -import chisel3._ - -class Coffee extends BlackBox { - val io = IO(new Bundle { - val I = Input(UInt(32.W)) - val O = Output(UInt(32.W)) - }) - override def desiredName = "Tea" -} - -class Salt extends Module { - val io = IO(new Bundle {}) - val drink = Module(new Coffee) - override def desiredName = "SodiumMonochloride" -} -``` - -Elaborating the Chisel module `Salt` yields our "desire name" for `Salt` and `Coffee` in the output Verilog: -```scala mdoc:passthrough -import chisel3.stage.{ChiselStage, ChiselGeneratorAnnotation} -import firrtl.annotations.DeletedAnnotation -import firrtl.EmittedVerilogCircuitAnnotation - -(new ChiselStage) - .execute(Array("-X", "verilog"), Seq(ChiselGeneratorAnnotation(() => new Salt))) - .collectFirst{ case DeletedAnnotation(_, a: EmittedVerilogCircuitAnnotation) => a.value.value } - .foreach(a => println(s"""|```verilog - |$a - |```""".stripMargin)) -``` diff --git a/docs/src/wiki-deprecated/data-types.md b/docs/src/wiki-deprecated/data-types.md deleted file mode 100644 index e931247f..00000000 --- a/docs/src/wiki-deprecated/data-types.md +++ /dev/null @@ -1,134 +0,0 @@ ---- -layout: docs -title: "Data Types" -section: "chisel3" ---- - -Chisel datatypes are used to specify the type of values held in state -elements or flowing on wires. While hardware designs ultimately -operate on vectors of binary digits, other more abstract -representations for values allow clearer specifications and help the -tools generate more optimal circuits. In Chisel, a raw collection of -bits is represented by the ```Bits``` type. Signed and unsigned integers -are considered subsets of fixed-point numbers and are represented by -types ```SInt``` and ```UInt``` respectively. Signed fixed-point -numbers, including integers, are represented using two's-complement -format. Boolean values are represented as type ```Bool```. Note -that these types are distinct from Scala's builtin types such as -```Int``` or ```Boolean```. - -> There is a new experimental type **Interval** which gives the developer more control of the type by allowing the definition of an IntervalRange. See: [Interval Type](interval-type) - -Additionally, Chisel defines `Bundles` for making -collections of values with named fields (similar to ```structs``` in -other languages), and ```Vecs``` for indexable collections of -values. - -Bundles and Vecs will be covered later. - -Constant or literal values are expressed using Scala integers or -strings passed to constructors for the types: -```scala -1.U // decimal 1-bit lit from Scala Int. -"ha".U // hexadecimal 4-bit lit from string. -"o12".U // octal 4-bit lit from string. -"b1010".U // binary 4-bit lit from string. - -5.S // signed decimal 4-bit lit from Scala Int. --8.S // negative decimal 4-bit lit from Scala Int. -5.U // unsigned decimal 3-bit lit from Scala Int. - -8.U(4.W) // 4-bit unsigned decimal, value 8. --152.S(32.W) // 32-bit signed decimal, value -152. - -true.B // Bool lits from Scala lits. -false.B -``` -Underscores can be used as separators in long string literals to aid -readability, but are ignored when creating the value, e.g.: -```scala -"h_dead_beef".U // 32-bit lit of type UInt -``` - -By default, the Chisel compiler will size each constant to the minimum -number of bits required to hold the constant, including a sign bit for -signed types. Bit widths can also be specified explicitly on -literals, as shown below. Note that (`.W` is used to cast a Scala Int -to a Chisel width) -```scala -"ha".asUInt(8.W) // hexadecimal 8-bit lit of type UInt -"o12".asUInt(6.W) // octal 6-bit lit of type UInt -"b1010".asUInt(12.W) // binary 12-bit lit of type UInt - -5.asSInt(7.W) // signed decimal 7-bit lit of type SInt -5.asUInt(8.W) // unsigned decimal 8-bit lit of type UInt -``` - -For literals of type ```UInt```, the value is -zero-extended to the desired bit width. For literals of type -```SInt```, the value is sign-extended to fill the desired bit width. -If the given bit width is too small to hold the argument value, then a -Chisel error is generated. - ->We are working on a more concise literal syntax for Chisel using -symbolic prefix operators, but are stymied by the limitations of Scala -operator overloading and have not yet settled on a syntax that is -actually more readable than constructors taking strings. - ->We have also considered allowing Scala literals to be automatically -converted to Chisel types, but this can cause type ambiguity and -requires an additional import. - ->The SInt and UInt types will also later support an optional exponent -field to allow Chisel to automatically produce optimized fixed-point -arithmetic circuits. - -## Casting - -We can also cast types in Chisel: - -```scala -val sint = 3.S(4.W) // 4-bit SInt - -val uint = sint.asUInt // cast SInt to UInt -uint.asSInt // cast UInt to SInt -``` - -**NOTE**: `asUInt`/`asSInt` with an explicit width can **not** be used to cast (convert) between Chisel datatypes. -No width parameter is accepted, as Chisel will automatically pad or truncate as required when the objects are connected. - -We can also perform casts on clocks, though you should be careful about this, since clocking (especially in ASIC) requires special attention: - -```scala -val bool: Bool = false.B // always-low wire -val clock = bool.asClock // always-low clock - -clock.asUInt // convert clock to UInt (width 1) -clock.asUInt.asBool // convert clock to Bool (Chisel 3.2+) -clock.asUInt.toBool // convert clock to Bool (Chisel 3.0 and 3.1 only) -``` - -## Analog/BlackBox type - -(Experimental, Chisel 3.1+) - -Chisel supports an `Analog` type (equivalent to Verilog `inout`) that can be used to support arbitrary nets in Chisel. This includes analog wires, tri-state/bi-directional wires, and power nets (with appropriate annotations). - -`Analog` is an undirectioned type, and so it is possible to connect multiple `Analog` nets together using the `attach` operator. It is possible to connect an `Analog` **once** using `<>` but illegal to do it more than once. - -```scala -val a = IO(Analog(1.W)) -val b = IO(Analog(1.W)) -val c = IO(Analog(1.W)) - -// Legal -attach(a, b) -attach(a, c) - -// Legal -a <> b - -// Illegal - connects 'a' multiple times -a <> b -a <> c -``` diff --git a/docs/src/wiki-deprecated/developers.md b/docs/src/wiki-deprecated/developers.md deleted file mode 100644 index 4c133c54..00000000 --- a/docs/src/wiki-deprecated/developers.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -layout: docs -title: "Developers" -section: "chisel3" ---- -# Developer Documentation - -Tips and tricks for Chisel developers. - -* [Embedding Chisel as an sbt subproject](sbt-subproject) -* [Test Coverage](test-coverage) diff --git a/docs/src/wiki-deprecated/faqs.md b/docs/src/wiki-deprecated/faqs.md deleted file mode 100644 index 45694cdc..00000000 --- a/docs/src/wiki-deprecated/faqs.md +++ /dev/null @@ -1,246 +0,0 @@ ---- -layout: docs -title: "Frequently Asked Questions" -section: "chisel3" ---- - -* [Where should I start if I want to learn Chisel?](#where-should-i-start-if-i-want-to-learn-chisel) -* [How do I ... in Chisel?](#how-do-i-do--eg-like-that-in-verilog-in-chisel) -* [How can I contribute to Chisel?](#how-can-i-contribute-to-chisel) -* [What is the difference between release and master branches?](#what-is-the-difference-between-release-and-master-branches) -* [Why DecoupledIO instead of ReadyValidIO?](#why-decoupledio-instead-of-readyvalidio) -* [Why do I have to wrap module instantiations in `Module(...)`?](#why-do-i-have-to-wrap-module-instantiations-in-module) -* [Why Chisel?](#why-chisel) -* [Does Chisel support X and Z logic values?](#does-chisel-support-x-and-z-logic-values) -* [I just want some Verilog; what do I do?](#get-me-verilog) -* [I just want some FIRRTL; what do I do?](#get-me-firrtl) -* [Why doesn't Chisel tell me which wires aren't connected?](#why-doesnt-chisel-tell-me-which-wires-arent-connected) -* [What does `Reference ... is not fully initialized.` mean?](#what-does-reference--is-not-fully-initialized-mean) -* [Can I specify behavior before and after generated initial blocks?](#can-i-specify-behavior-before-and-after-generated-initial-blocks) - -### Where should I start if I want to learn Chisel? - -We recommend the [Chisel Bootcamp](https://github.com/freechipsproject/chisel-bootcamp) for getting started with Chisel. - -### How do I do ... (e.g. like that in Verilog) in Chisel? - -See the [cookbook](cookbook). - -### How can I contribute to Chisel? - -A good to place to start is to fill out the [How Can I Contribute Form](https://docs.google.com/forms/d/e/1FAIpQLSfwTTY8GkfSZ2sU2T2mNpfNMpIM70GlXOrjqiHoC9ZBvwn_CA/viewform). - -### What is the difference between release and master branches? - -We have two main branches for each main Chisel project: - -- `master` -- `release` - -`master` is the main development branch and it is updated frequently (often several times a day). -Although we endeavour to keep the `master` branches in sync, they may drift out of sync for a day or two. -We do not publish the `master` branches. -If you wish to use them, you need to clone the GitHub repositories and use `sbt publishLocal` to make them available on your local machine. - -The `release` branches are updated less often (currently bi-weekly) and we try to guarantee they are in sync. -We publish these to Sonatype/Maven on a bi-weekly basis. - -In general, you can not mix `release` and `master` branches and assume they will work. - -The default branches for the user-facing repositories (chisel-template and chisel-tutorial) are the `release` branches - these should always *just work* for new users as they use the `release` branches of chisel projects. - -If you want to use something more current than the `release` branch, you should `git checkout master` for all the chisel repos you intend to use, then `sbt publishLocal` them in this order: - -- firrtl -- firrtl-interpreter -- chisel3 -- chisel-testers - -Then, if you're working with the user-facing repositories: - -- chisel-tutorial -- chisel-template - -Since this is a substantial amount of work (with no guarantee of success), unless you are actively involved in Chisel development, we encourage you to stick with the `release` branches and their respective dependencies. - -### Why DecoupledIO instead of ReadyValidIO? - -There are multiple kinds of Ready/Valid interfaces that impose varying restrictions on the producers and consumers. Chisel currently provides the following: - -* [DecoupledIO](https://chisel.eecs.berkeley.edu/api/index.html#chisel3.util.DecoupledIO) - No guarantees -* [IrrevocableIO](https://chisel.eecs.berkeley.edu/api/index.html#chisel3.util.IrrevocableIO) - Producer promises to not change the value of 'bits' after a cycle where 'valid' is high and 'ready' is low. Additionally, once 'valid' is raised it will never be lowered until after 'ready' has also been raised. - -### Why do I have to wrap module instantiations in `Module(...)`? - -In short: Limitations of Scala - -Chisel Modules are written by defining a [Scala class](http://docs.scala-lang.org/tutorials/tour/classes.html) and implementing its constructor. As elaboration runs, Chisel constructs a hardware AST from these Modules. The compiler needs hooks to run before and after the actual construction of the Module object. In Scala, superclasses are fully initialized before subclasses, so by extending Module, Chisel has the ability to run some initialization code before the user's Module is constructed. However, there is no such hook to run after the Module object is initialized. By wrapping Module instantiations in the Module object's apply method (ie. `Module(...)`), Chisel is able to perform post-initialization actions. There is a [proposed solution](https://issues.scala-lang.org/browse/SI-4330), so eventually this requirement will be lifted, but for now, wrap those Modules! - -### Why Chisel? - -Borrowed from [Chisel Introduction](introduction) - ->We were motivated to develop a new hardware language by years of -struggle with existing hardware description languages in our research -projects and hardware design courses. _Verilog_ and _VHDL_ were developed -as hardware _simulation_ languages, and only later did they become -a basis for hardware _synthesis_. Much of the semantics of these -languages are not appropriate for hardware synthesis and, in fact, -many constructs are simply not synthesizable. Other constructs are -non-intuitive in how they map to hardware implementations, or their -use can accidently lead to highly inefficient hardware structures. -While it is possible to use a subset of these languages and still get -acceptable results, they nonetheless present a cluttered and confusing -specification model, particularly in an instructional setting. - ->However, our strongest motivation for developing a new hardware -language is our desire to change the way that electronic system design -takes place. We believe that it is important to not only teach -students how to design circuits, but also to teach them how to design -*circuit generators* ---programs that automatically generate -designs from a high-level set of design parameters and constraints. -Through circuit generators, we hope to leverage the hard work of -design experts and raise the level of design abstraction for everyone. -To express flexible and scalable circuit construction, circuit -generators must employ sophisticated programming techniques to make -decisions concerning how to best customize their output circuits -according to high-level parameter values and constraints. While -Verilog and VHDL include some primitive constructs for programmatic -circuit generation, they lack the powerful facilities present in -modern programming languages, such as object-oriented programming, -type inference, support for functional programming, and reflection. - ->Instead of building a new hardware design language from scratch, we -chose to embed hardware construction primitives within an existing -language. We picked Scala not only because it includes the -programming features we feel are important for building circuit -generators, but because it was specifically developed as a base for -domain-specific languages. - -### Does Chisel support X and Z logic values - -Chisel does not directly support Verilog logic values ```x``` *unknown* and ```z``` *high-impedance*. There are a number of reasons to want to avoid these values. See:[The Dangers of Living With An X](http://infocenter.arm.com/help/topic/com.arm.doc.arp0009a/Verilog_X_Bugs.pdf) and [Malicious LUT: A stealthy FPGA Trojan injected and triggered by the design flow](http://ieeexplore.ieee.org/document/7827620/). Chisel has it's own eco-system of unit and functional testers that limit the need for ```x``` and ```z``` and their omission simplify language implementation, design, and testing. The circuits created by chisel do not preclude developers from using ```x``` and ```z``` in downstream toolchains as they see fit. - -### Get me Verilog -I wrote a module and I want to see the Verilog; what do I do? - -Here's a simple hello world module in a file HelloWorld.scala. - -```scala -package intro -import chisel3._ -class HelloWorld extends Module { - val io = IO(new Bundle{}) - printf("hello world\n") -} -``` -Add the following -```scala -object HelloWorld extends App { - chisel3.Driver.execute(args, () => new HelloWorld) -} -``` -Now you can get some Verilog. Start sbt: -``` -bash> sbt -> run-main intro.HelloWorld -[info] Running examples.HelloWorld -[info] [0.004] Elaborating design... -[info] [0.100] Done elaborating. -[success] Total time: 1 s, completed Jan 12, 2017 6:24:03 PM -``` -or as a one-liner: -``` -bash> sbt 'runMain intro.HelloWorld' -``` -After either of the above there will be a HelloWorld.v file in the current directory. - -You can see additional options with -``` -bash> sbt 'runMain intro.HelloWorld --help' -``` -This will return a comprehensive usage line with available options. - -For example to place the output in a directory name buildstuff use -``` -bash> sbt 'runMain intro.HelloWorld --target-dir buildstuff --top-name HelloWorld' -``` - -Alternatively, you can also use the sbt console to invoke the Verilog driver: - -``` -$ sbt -> console -[info] Starting scala interpreter... -[info] -Welcome to Scala 2.11.8 (OpenJDK 64-Bit Server VM, Java 1.8.0_121). -Type in expressions for evaluation. Or try :help. -scala> chisel3.Driver.execute(Array[String](), () => new HelloWorld) -chisel3.Driver.execute(Array[String](), () => new HelloWorld) -[info] [0.014] Elaborating design... -[info] [0.306] Done elaborating. -Total FIRRTL Compile Time: 838.8 ms -res3: chisel3.ChiselExecutionResult = [...] -``` - -As before, there should be a HelloWorld.v file in the current directory. - -### Get me FIRRTL - -If for some reason you don't want the Verilog (e.g. maybe you want to run some custom transformations before exporting to Verilog), then use something along these lines (replace Multiplier with your module): - -```scala -package intro - -import chisel3._ -import java.io.File - -object Main extends App { - val f = new File("Multiplier.fir") - chisel3.Driver.dumpFirrtl(chisel3.Driver.elaborate(() => new Multiplier), Option(f)) -} -``` - -Run it with: - -``` -sbt 'runMain intro.Main' -``` - -Alternatively, you can also use the sbt console to invoke the FIRRTL driver directly (replace HelloWorld with your module name): - -``` -$ sbt -> console -[info] Starting scala interpreter... -[info] -Welcome to Scala 2.11.11 (OpenJDK 64-Bit Server VM, Java 1.8.0_151). -Type in expressions for evaluation. Or try :help. -scala> chisel3.Driver.dumpFirrtl(chisel3.Driver.elaborate(() => new HelloWorld), Option(new java.io.File("output.fir"))) -chisel3.Driver.dumpFirrtl(chisel3.Driver.elaborate(() => new HelloWorld), Option(new java.io.File("output.fir"))) -[info] [0.000] Elaborating design... -[info] [0.001] Done elaborating. -res3: java.io.File = output.fir -``` - -### Why doesn't Chisel tell me which wires aren't connected? - -As of commit [c313e13](https://github.com/freechipsproject/chisel3/commit/c313e137d4e562ef20195312501840ceab8cbc6a) it can! -Please visit the wiki page [Unconnected Wires](unconnected-wires) for details. - -### What does `Reference ... is not fully initialized.` mean? - -It means that you have unconnected wires in your design which could be an indication of a design bug. - -In Chisel2 compatibility mode (`NotStrict` compile options), chisel generates firrtl code that disables firrtl's initialized wire checks. -In pure chisel3 (`Strict` compile options), the generated firrtl code does not contain these disablers (`is invalid`). -Output wires that are not driven (not connected) are reported by firrtl as `not fully initialized`. -Please visit the wiki page [Unconnected Wires](unconnected-wires) for details on solving the problem. - -### Can I specify behavior before and after generated initial blocks? -Users may define the following macros if they wish to specify behavior before or after emitted initial blocks. - -* `BEFORE_INITIAL`, which is called before the emitted (non-empty) initial block if it is defined -* `AFTER_INITIAL`, which is called after the emitted (non-empty) initial block if it is defined - -These macros may be useful for turning coverage on and off. diff --git a/docs/src/wiki-deprecated/functional-abstraction.md b/docs/src/wiki-deprecated/functional-abstraction.md deleted file mode 100644 index 04dde7d1..00000000 --- a/docs/src/wiki-deprecated/functional-abstraction.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -layout: docs -title: "Functional Abstraction" -section: "chisel3" ---- -We can define functions to factor out a repeated piece of logic that -we later reuse multiple times in a design. For example, we can wrap -up our earlier example of a simple combinational logic block as -follows: -```scala -def clb(a: UInt, b: UInt, c: UInt, d: UInt): UInt = - (a & b) | (~c & d) -``` - -where ```clb``` is the function which takes ```a```, ```b```, -```c```, ```d``` as arguments and returns a wire to the output of a -boolean circuit. The ```def``` keyword is part of Scala and -introduces a function definition, with each argument followed by a colon then its type, -and the function return type given after the colon following the -argument list. The equals (```=})```sign separates the function argument list from the function -definition. - -We can then use the block in another circuit as follows: -```scala -val out = clb(a,b,c,d) -``` - -We will later describe many powerful ways to use functions to -construct hardware using Scala's functional programming support. diff --git a/docs/src/wiki-deprecated/functional-module-creation.md b/docs/src/wiki-deprecated/functional-module-creation.md deleted file mode 100644 index 3e2e95bc..00000000 --- a/docs/src/wiki-deprecated/functional-module-creation.md +++ /dev/null @@ -1,79 +0,0 @@ ---- -layout: docs -title: "Functional Module Creation" -section: "chisel3" ---- -Objects in Scala have a pre-existing creation function (method) called `apply`. -When an object is used as value in an expression (which basically means that the constructor was called), this method determines the returned value. -When dealing with hardware modules, one would expect the module output to be representative of the hardware module's functionality. -Therefore, we would sometimes like the module output to be the value returned when using the object as a value in an expression. -Since hardware modules are represented as Scala objects, this can be done by defining the object's `apply` method to return the module's output. -This can be referred to as creating a functional interface for module construction. -If we apply this on the standard mux2 example, we would to return the mux2 output ports when we used mux2 in an expression. -Implementing this requires building a constructor that takes multiplexer inputs as parameters and returns the multiplexer output: - -```scala -object Mux2 { - def apply(sel: UInt, in0: UInt, in1: UInt) = { - val m = Module(new Mux2) - m.io.in0 := in0 - m.io.in1 := in1 - m.io.sel := sel - m.io.out - } -} -``` - -As we can see in the code example, we defined the `apply` method to take the Mux2 inputs as the method parameters, and return the Mux2 output as the function's return value. -By defining modules in this way, it is easier to later implement larger and more complex version of this regular module. -For example, we previously implemented Mux4 like this: - -```scala -class Mux4 extends Module { - val io = IO(new Bundle { - val in0 = Input(UInt(1.W)) - val in1 = Input(UInt(1.W)) - val in2 = Input(UInt(1.W)) - val in3 = Input(UInt(1.W)) - val sel = Input(UInt(2.W)) - val out = Output(UInt(1.W)) - }) - val m0 = Module(new Mux2) - m0.io.sel := io.sel(0) - m0.io.in0 := io.in0 - m0.io.in1 := io.in1 - - val m1 = Module(new Mux2) - m1.io.sel := io.sel(0) - m1.io.in0 := io.in2 - m1.io.in1 := io.in3 - - val m3 = Module(new Mux2) - m3.io.sel := io.sel(1) - m3.io.in0 := m0.io.out - m3.io.in1 := m1.io.out - - io.out := m3.io.out -} -``` - -However, by using the creation function we redefined for Mux2, we can now use the Mux2 outputs as values of the modules themselves -when writing the Mux4 output expression: - -```scala -class Mux4 extends Module { - val io = IO(new Bundle { - val in0 = Input(UInt(1.W)) - val in1 = Input(UInt(1.W)) - val in2 = Input(UInt(1.W)) - val in3 = Input(UInt(1.W)) - val sel = Input(UInt(2.W)) - val out = Output(UInt(1.W)) - }) - io.out := Mux2(io.sel(1), - Mux2(io.sel(0), io.in0, io.in1), - Mux2(io.sel(0), io.in2, io.in3)) -} -``` - -This allows to write more intuitively readable hardware connection descriptions, which are similar to software expression evaluation. diff --git a/docs/src/wiki-deprecated/interfaces-and-connections.md b/docs/src/wiki-deprecated/interfaces-and-connections.md deleted file mode 100644 index 5902f5cd..00000000 --- a/docs/src/wiki-deprecated/interfaces-and-connections.md +++ /dev/null @@ -1,144 +0,0 @@ ---- -layout: docs -title: "Interfaces and Connections" -section: "chisel3" ---- -# Interfaces & Bulk Connections - -For more sophisticated modules it is often useful to define and instantiate interface classes while defining the IO for a module. First and foremost, interface classes promote reuse allowing users to capture once and for all common interfaces in a useful form. - -Secondly, interfaces allow users to dramatically reduce wiring by supporting bulk connections between producer and consumer modules. Finally, users can make changes in large interfaces in one place reducing the number of updates required when adding or removing pieces of the interface. - -Note that Chisel has some built-in standard interface which should be used whenever possible for interoperability (e.g. Decoupled). - -## Ports: Subclasses & Nesting - -As we saw earlier, users can define their own interfaces by defining a class that subclasses Bundle. For example, a user could define a simple link for hand-shaking data as follows: - -```scala -class SimpleLink extends Bundle { - val data = Output(UInt(16.W)) - val valid = Output(Bool()) -} -``` - -We can then extend SimpleLink by adding parity bits using bundle inheritance: -```scala -class PLink extends SimpleLink { - val parity = Output(UInt(5.W)) -} -``` -In general, users can organize their interfaces into hierarchies using inheritance. - -From there we can define a filter interface by nesting two PLinks into a new FilterIO bundle: -```scala -class FilterIO extends Bundle { - val x = Flipped(new PLink) - val y = new PLink -} -``` -where flip recursively changes the direction of a bundle, changing input to output and output to input. - -We can now define a filter by defining a filter class extending module: -```scala -class Filter extends Module { - val io = IO(new FilterIO) - ... -} -``` -where the io field contains FilterIO. - -## Bundle Vectors - -Beyond single elements, vectors of elements form richer hierarchical interfaces. For example, in order to create a crossbar with a vector of inputs, producing a vector of outputs, and selected by a UInt input, we utilize the Vec constructor: -```scala -import chisel3.util.log2Ceil -class CrossbarIo(n: Int) extends Bundle { - val in = Vec(n, Flipped(new PLink)) - val sel = Input(UInt(log2Ceil(n).W)) - val out = Vec(n, new PLink) -} -``` -where Vec takes a size as the first argument and a block returning a port as the second argument. - -## Bulk Connections - -We can now compose two filters into a filter block as follows: -```scala -class Block extends Module { - val io = IO(new FilterIO) - val f1 = Module(new Filter) - val f2 = Module(new Filter) - f1.io.x <> io.x - f1.io.y <> f2.io.x - f2.io.y <> io.y -} -``` -where <> bulk connects interfaces of opposite gender between sibling modules or interfaces of the same gender between parent/child modules. - -Bulk connections connect leaf ports of the same name to each other. If the names do not match or are missing, Chisel does not generate a connection. - -Caution: bulk connections should only be used with **directioned elements** (like IOs), and is not magical (e.g. connecting two wires isn't supported since Chisel can't necessarily figure out the directions automatically [chisel3#603](https://github.com/freechipsproject/chisel3/issues/603)). - -## The standard ready-valid interface (ReadyValidIO / Decoupled) - -Chisel provides a standard interface for [ready-valid interfaces](http://inst.eecs.berkeley.edu/~cs150/Documents/Interfaces.pdf). -A ready-valid interface consists of a `ready` signal, a `valid` signal, and some data stored in `bits`. -The `ready` bit indicates that a consumer is *ready* to consume data. -The `valid` bit indicates that a producer has *valid* data on `bits`. -When both `ready` and `valid` are asserted, a data transfer from the producer to the consumer takes place. -A convenience method `fire` is provided that is asserted if both `ready` and `valid` are asserted. - -Usually, we use the utility function [`Decoupled()`](https://chisel.eecs.berkeley.edu/api/latest/chisel3/util/Decoupled$.html) to turn any type into a ready-valid interface rather than directly using [ReadyValidIO](http://chisel.eecs.berkeley.edu/api/latest/chisel3/util/ReadyValidIO.html). - -* `Decoupled(...)` creates a producer / output ready-valid interface (i.e. bits is an output). -* `Flipped(Decoupled(...))` creates a consumer / input ready-valid interface (i.e. bits is an input). - -Take a look at the following example Chisel code to better understand exactly what is generated: - -```scala -import chisel3._ -import chisel3.util.Decoupled - -/** - * Using Decoupled(...) creates a producer interface. - * i.e. it has bits as an output. - * This produces the following ports: - * input io_readyValid_ready, - * output io_readyValid_valid, - * output [31:0] io_readyValid_bits - */ -class ProducingData extends Module { - val io = IO(new Bundle { - val readyValid = Decoupled(UInt(32.W)) - }) - // do something with io.readyValid.ready - io.readyValid.valid := true.B - io.readyValid.bits := 5.U -} - -/** - * Using Flipped(Decoupled(...)) creates a consumer interface. - * i.e. it has bits as an input. - * This produces the following ports: - * output io_readyValid_ready, - * input io_readyValid_valid, - * input [31:0] io_readyValid_bits - */ -class ConsumingData extends Module { - val io = IO(new Bundle { - val readyValid = Flipped(Decoupled(UInt(32.W))) - }) - io.readyValid.ready := false.B - // do something with io.readyValid.valid - // do something with io.readyValid.bits -} -``` - -`DecoupledIO` is a ready-valid interface with the *convention* that there are no guarantees placed on deasserting `ready` or `valid` or on the stability of `bits`. -That means `ready` and `valid` can also be deasserted without a data transfer. - -`IrrevocableIO` is a ready-valid interface with the *convention* that the value of `bits` will not change while `valid` is asserted and `ready` is deasserted. -Also the consumer shall keep `ready` asserted after a cycle where `ready` was high and `valid` was low. -Note that the *irrevocable* constraint *is only a convention* and cannot be enforced by the interface. -Chisel does not automatically generate checkers or assertions to enforce the *irrevocable* convention. diff --git a/docs/src/wiki-deprecated/interval-type.md b/docs/src/wiki-deprecated/interval-type.md deleted file mode 100644 index 7f33461e..00000000 --- a/docs/src/wiki-deprecated/interval-type.md +++ /dev/null @@ -1,55 +0,0 @@ -# Intervals -**Intervals** are a new experimental numeric type that comprises UInt, SInt and FixedPoint numbers. -It augments these types with range information, i.e. upper and lower numeric bounds. -This information can be used to exercise tighter programmatic control over the ultimate widths of -signals in the final circuit. The **Firrtl** compiler can infer this range information based on -operations and earlier values in the circuit. Intervals support all the ordinary bit and arithmetic operations -associated with UInt, SInt, and FixedPoint and adds the following methods for manipulating the range of -a **source** Interval with the IntervalRange of **target** Interval - -### Clip -- Fit the value **source** into the IntervalRange of **target**, saturate if out of bounds -The clip method applied to an interval creates a new interval based on the argument to clip, -and constructs the necessary hardware so that the source Interval's value will be mapped into the new Interval. -Values that are outside the result range will be pegged to either maximum or minimum of result range as appropriate. - -> Generates necessary hardware to clip values, values greater than range are set to range.high, values lower than range are set to range min. - -### Wrap -- Fit the value **source** into the IntervalRange of **target**, wrapping around if out of bounds -The wrap method applied to an interval creates a new interval based on the argument to wrap, -and constructs the necessary -hardware so that the source Interval's value will be mapped into the new Interval. -Values that are outside the result range will be wrapped until they fall within the result range. - -> Generates necessary hardware to wrap values, values greater than range are set to range.high, values lower than range are set to range min. - -> Does not handle out of range values that are less than half the minimum or greater than twice maximum - -### Squeeze -- Fit the value **source** into the smallest IntervalRange based on source and target. -The squeeze method applied to an interval creates a new interval based on the argument to clip, the two ranges must overlap -behavior of squeeze with inputs outside of the produced range is undefined. - -> Generates no hardware, strictly a sizing operation - -#### Range combinations - -| Condition | A.clip(B) | A.wrap(B) | A.squeeze(B) | -| --------- | --------------- | --------------- | --------------- | -| A === B | max(Alo, Blo), min(Ahi, Bhi) | max(Alo, Blo), min(Ahi, Bhi) | max(Alo, Blo), min(Ahi, Bhi) | -| A contains B | max(Alo, Blo), min(Ahi, Bhi) | max(Alo, Blo), min(Ahi, Bhi) | max(Alo, Blo), min(Ahi, Bhi) | -| B contains A | max(Alo, Blo), min(Ahi, Bhi) | max(Alo, Blo), min(Ahi, Bhi) | max(Alo, Blo), min(Ahi, Bhi) | -| A min < B min, A max in B | max(Alo, Blo), min(Ahi, Bhi) | max(Alo, Blo), min(Ahi, Bhi) | max(Alo, Blo), min(Ahi, Bhi) | -| A min in B, A max > B max | max(Alo, Blo), min(Ahi, Bhi) | max(Alo, Blo), min(Ahi, Bhi) | max(Alo, Blo), min(Ahi, Bhi) | -| A strictly less than B | error | error | error | -| A strictly greater than B | error | error | error | - - -### Applying binary point operators to an Interval - -Consider a Interval with a binary point of 3: aaa.bbb - -| operation | after operation | binary point | lower | upper | meaning | -| --------- | --------------- | ------------ | ----- | ----- | ------- | -| setBinaryPoint(2) | aaa.bb | 2 | X | X | set the precision | -| shiftLeftBinaryPoint(2) | a.aabbb | 5 | X | X | increase the precision | -| shiftRighBinaryPoint(2) | aaaa.b | 1 | X | X | reduce the precision | - diff --git a/docs/src/wiki-deprecated/introduction.md b/docs/src/wiki-deprecated/introduction.md deleted file mode 100644 index 43fc9887..00000000 --- a/docs/src/wiki-deprecated/introduction.md +++ /dev/null @@ -1,64 +0,0 @@ ---- -layout: docs -title: "Introduction" -section: "chisel3" ---- -This document is a tutorial introduction to _Chisel_ (Constructing -Hardware In a Scala Embedded Language). Chisel is a hardware -construction language embedded in the high-level programming language -Scala. At some point we will provide a proper reference manual, in -addition to more tutorial examples. In the meantime, this document -along with a lot of trial and error should set you on your way to -using Chisel. _Chisel is really only a set of special class -definitions, predefined objects, and usage conventions within Scala, -so when you write Chisel you are actually writing a Scala -program that constructs a hardware graph._ However, for the tutorial we don't presume that you -understand how to program in Scala. We will point out necessary Scala -features through the Chisel examples we give, and significant hardware -designs can be completed using only the material contained herein. -But as you gain experience and want to make your code simpler or more -reusable, you will find it important to leverage the underlying power -of the Scala language. We recommend you consult one of the excellent -Scala books to become more expert in Scala programming. - ->Through the tutorial, we format commentary on our design choices as in -this paragraph. You should be able to skip the commentary sections -and still fully understand how to use Chisel, but we hope you'll find -them interesting. - ->We were motivated to develop a new hardware language by years of -struggle with existing hardware description languages in our research -projects and hardware design courses. _Verilog_ and _VHDL_ were developed -as hardware _simulation_ languages, and only later did they become -a basis for hardware _synthesis_. Much of the semantics of these -languages are not appropriate for hardware synthesis and, in fact, -many constructs are simply not synthesizable. Other constructs are -non-intuitive in how they map to hardware implementations, or their -use can accidentally lead to highly inefficient hardware structures. -While it is possible to use a subset of these languages and still get -acceptable results, they nonetheless present a cluttered and confusing -specification model, particularly in an instructional setting. - ->However, our strongest motivation for developing a new hardware -language is our desire to change the way that electronic system design -takes place. We believe that it is important to not only teach -students how to design circuits, but also to teach them how to design -*circuit generators* ---programs that automatically generate -designs from a high-level set of design parameters and constraints. -Through circuit generators, we hope to leverage the hard work of -design experts and raise the level of design abstraction for everyone. -To express flexible and scalable circuit construction, circuit -generators must employ sophisticated programming techniques to make -decisions concerning how to best customize their output circuits -according to high-level parameter values and constraints. While -Verilog and VHDL include some primitive constructs for programmatic -circuit generation, they lack the powerful facilities present in -modern programming languages, such as object-oriented programming, -type inference, support for functional programming, and reflection. - ->Instead of building a new hardware design language from scratch, we -chose to embed hardware construction primitives within an existing -language. We picked Scala not only because it includes the -programming features we feel are important for building circuit -generators, but because it was specifically developed as a base for -domain-specific languages. diff --git a/docs/src/wiki-deprecated/memories.md b/docs/src/wiki-deprecated/memories.md deleted file mode 100644 index e4b9a80b..00000000 --- a/docs/src/wiki-deprecated/memories.md +++ /dev/null @@ -1,170 +0,0 @@ ---- -layout: docs -title: "Memories" -section: "chisel3" ---- -Chisel provides facilities for creating both read only and read/write memories. - -## ROM - -Users can define read only memories with a `Vec`: - -``` scala - VecInit(inits: Seq[T]) - VecInit(elt0: T, elts: T*) -``` - -where `inits` is a sequence of initial `Data` literals that initialize the ROM. For example, users cancreate a small ROM initialized to 1, 2, 4, 8 and loop through all values using a counter as an address generator as follows: - -``` scala - val m = VecInit(Array(1.U, 2.U, 4.U, 8.U)) - val r = m(counter(m.length.U)) -``` - -We can create an *n* value sine lookup table using a ROM initialized as follows: - -``` scala - def sinTable(amp: Double, n: Int) = { - val times = - (0 until n).map(i => (i*2*Pi)/(n.toDouble-1) - Pi) - val inits = - times.map(t => round(amp * sin(t)).asSInt(32.W)) - VecInit(inits) - } - def sinWave(amp: Double, n: Int) = - sinTable(amp, n)(counter(n.U)) -``` - -where `amp` is used to scale the fixpoint values stored in the ROM. - -## Memories - -Memories are given special treatment in Chisel since hardware implementations of memory vary greatly. For example, FPGA memories are instantiated quite differently from ASIC memories. Chisel defines a memory abstraction that can map to either simple Verilog behavioural descriptions or to instances of memory modules that are available from external memory generators provided by foundry or IP vendors. - - -### `SyncReadMem`: sequential/synchronous-read, sequential/synchronous-write - -Chisel has a construct called `SyncReadMem` for sequential/synchronous-read, sequential/synchronous-write memories. These `SyncReadMem`s will likely be synthesized to technology SRAMs (as opposed to register banks). - -If the same memory address is both written and sequentially read on the same clock edge, or if a sequential read enable is cleared, then the read data is undefined. - -Values on the read data port are not guaranteed to be held until the next read cycle. If that is the desired behavior, external logic to hold the last read value must be added. - -#### Read port/write port -Ports into `SyncReadMem`s are created by applying a `UInt` index. A 1024-entry SRAM with one write port and one read port might be expressed as follows: - -```scala mdoc:silent -import chisel3._ -class ReadWriteSmem extends Module { - val width: Int = 32 - val io = IO(new Bundle { - val enable = Input(Bool()) - val write = Input(Bool()) - val addr = Input(UInt(10.W)) - val dataIn = Input(UInt(width.W)) - val dataOut = Output(UInt(width.W)) - }) - - val mem = SyncReadMem(1024, UInt(width.W)) - // Create one write port and one read port - mem.write(io.addr, io.dataIn) - io.dataOut := mem.read(io.addr, io.enable) -} -``` - -Below is an example waveform of the one write port/one read port `SyncReadMem` with [masks](#masks). Note that the signal names will differ from the exact wire names generated for the `SyncReadMem`. With masking, it is also possible that multiple RTL arrays will be generated with the behavior below. - -![read/write ports example waveform](https://svg.wavedrom.com/github/freechipsproject/www.chisel-lang.org/master/docs/src/main/tut/chisel3/memories_waveforms/smem_read_write.json) - -#### Single-ported -Single-ported SRAMs can be inferred when the read and write conditions are mutually exclusive in the same `when` chain: - -```scala mdoc:silent -import chisel3._ -class RWSmem extends Module { - val width: Int = 32 - val io = IO(new Bundle { - val enable = Input(Bool()) - val write = Input(Bool()) - val addr = Input(UInt(10.W)) - val dataIn = Input(UInt(width.W)) - val dataOut = Output(UInt(width.W)) - }) - - val mem = SyncReadMem(1024, UInt(width.W)) - io.dataOut := DontCare - when(io.enable) { - val rdwrPort = mem(io.addr) - when (io.write) { rdwrPort := io.dataIn } - .otherwise { io.dataOut := rdwrPort } - } -} -``` - -(The `DontCare` is there to make Chisel's [unconnected wire detection](unconnected-wires) aware that reading while writing is undefined.) - -Here is an example single read/write port waveform, with [masks](#masks) (again, generated signal names and number of arrays may differ): - -![read/write ports example waveform](https://svg.wavedrom.com/github/freechipsproject/www.chisel-lang.org/master/docs/src/main/tut/chisel3/memories_waveforms/smem_rw.json) - -### `Mem`: combinational/asynchronous-read, sequential/synchronous-write - -Chisel supports random-access memories via the `Mem` construct. Writes to `Mem`s are combinational/asynchronous-read, sequential/synchronous-write. These `Mem`s will likely be synthesized to register banks, since most SRAMs in modern technologies (FPGA, ASIC) tend to no longer support combinational (asynchronous) reads. - -Creating asynchronous-read versions of the examples above simply involves replacing `SyncReadMem` with `Mem`. - -### Masks - -Chisel memories also support write masks for subword writes. Chisel will infer masks if the data type of the memory is a vector. To infer a mask, specify the `mask` argument of the `write` function which creates write ports. A given masked length is written if the corresponding mask bit is set. For example, in the example below, if the 0th bit of mask is true, it will write the lower byte of the data at corresponding address. - -```scala mdoc:silent -import chisel3._ -class MaskedReadWriteSmem extends Module { - val width: Int = 8 - val io = IO(new Bundle { - val enable = Input(Bool()) - val write = Input(Bool()) - val addr = Input(UInt(10.W)) - val mask = Input(Vec(4, Bool())) - val dataIn = Input(Vec(4, UInt(width.W))) - val dataOut = Output(Vec(4, UInt(width.W))) - }) - - // Create a 32-bit wide memory that is byte-masked - val mem = SyncReadMem(1024, Vec(4, UInt(width.W))) - // Write with mask - mem.write(io.addr, io.dataIn, io.mask) - io.dataOut := mem.read(io.addr, io.enable) -} -``` - -Here is an example of masks with readwrite ports: - -```scala mdoc:silent -import chisel3._ -class MaskedRWSmem extends Module { - val width: Int = 32 - val io = IO(new Bundle { - val enable = Input(Bool()) - val write = Input(Bool()) - val mask = Input(Vec(2, Bool())) - val addr = Input(UInt(10.W)) - val dataIn = Input(Vec(2, UInt(width.W))) - val dataOut = Output(Vec(2, UInt(width.W))) - }) - - val mem = SyncReadMem(1024, Vec(2, UInt(width.W))) - io.dataOut := DontCare - when(io.enable) { - val rdwrPort = mem(io.addr) - when (io.write) { - when(io.mask(0)) { - rdwrPort(0) := io.dataIn(0) - } - when(io.mask(1)) { - rdwrPort(1) := io.dataIn(1) - } - }.otherwise { io.dataOut := rdwrPort } - } -} -``` diff --git a/docs/src/wiki-deprecated/modules.md b/docs/src/wiki-deprecated/modules.md deleted file mode 100644 index 23006c9c..00000000 --- a/docs/src/wiki-deprecated/modules.md +++ /dev/null @@ -1,135 +0,0 @@ ---- -layout: docs -title: "Modules" -section: "chisel3" ---- -Chisel *modules* are very similar to Verilog *modules* in -defining a hierarchical structure in the generated circuit. - -The hierarchical module namespace is accessible in downstream tools -to aid in debugging and physical layout. A user-defined module is -defined as a *class* which: - - - inherits from `Module`, - - contains at least one interface wrapped in a Module's `IO()` method (traditionally stored in a port field named ```io```), and - - wires together subcircuits in its constructor. - -As an example, consider defining your own two-input multiplexer as a -module: -```scala mdoc:silent -import chisel3._ -class Mux2IO extends Bundle { - val sel = Input(UInt(1.W)) - val in0 = Input(UInt(1.W)) - val in1 = Input(UInt(1.W)) - val out = Output(UInt(1.W)) -} - -class Mux2 extends Module { - val io = IO(new Mux2IO) - io.out := (io.sel & io.in1) | (~io.sel & io.in0) -} -``` - -The wiring interface to a module is a collection of ports in the -form of a ```Bundle```. The interface to the module is defined -through a field named ```io```. For ```Mux2```, ```io``` is -defined as a bundle with four fields, one for each multiplexer port. - -The ```:=``` assignment operator, used here in the body of the -definition, is a special operator in Chisel that wires the input of -left-hand side to the output of the right-hand side. - -### Module Hierarchy - -We can now construct circuit hierarchies, where we build larger modules out -of smaller sub-modules. For example, we can build a 4-input -multiplexer module in terms of the ```Mux2``` module by wiring -together three 2-input multiplexers: - -```scala mdoc:silent -class Mux4IO extends Bundle { - val in0 = Input(UInt(1.W)) - val in1 = Input(UInt(1.W)) - val in2 = Input(UInt(1.W)) - val in3 = Input(UInt(1.W)) - val sel = Input(UInt(2.W)) - val out = Output(UInt(1.W)) -} -class Mux4 extends Module { - val io = IO(new Mux4IO) - - val m0 = Module(new Mux2) - m0.io.sel := io.sel(0) - m0.io.in0 := io.in0 - m0.io.in1 := io.in1 - - val m1 = Module(new Mux2) - m1.io.sel := io.sel(0) - m1.io.in0 := io.in2 - m1.io.in1 := io.in3 - - val m3 = Module(new Mux2) - m3.io.sel := io.sel(1) - m3.io.in0 := m0.io.out - m3.io.in1 := m1.io.out - - io.out := m3.io.out -} -``` - -We again define the module interface as ```io``` and wire up the -inputs and outputs. In this case, we create three ```Mux2``` -children modules, using the ```Module``` constructor function and -the Scala ```new``` keyword to create a -new object. We then wire them up to one another and to the ports of -the ```Mux4``` interface. - -Note: Chisel `Module`s have an implicit clock (called `clock`) and -an implicit reset (called `reset`). To create modules without implicit -clock and reset, Chisel provides `RawModule`. - -> Historical Note: Prior to Chisel 3.5, Modules were restricted to only -having a single user-defined port named `io`. There was also a type called -`MultiIOModule` that provided implicit clock and reset while allowing the -user to define as many ports as they want. This is now the functionality -of `Module`. - -### `RawModule` - -A `RawModule` is a module that **does not provide an implicit clock and reset.** -This can be useful when interfacing a Chisel module with a design that expects -a specific naming convention for clock or reset. - -Then we can use it in place of *Module* usage : -```scala mdoc:silent -import chisel3.{RawModule, withClockAndReset} - -class Foo extends Module { - val io = IO(new Bundle{ - val a = Input(Bool()) - val b = Output(Bool()) - }) - io.b := !io.a -} - -class FooWrapper extends RawModule { - val a_i = IO(Input(Bool())) - val b_o = IO(Output(Bool())) - val clk = Input(Clock()) - val rstn = Input(Bool()) - - val foo = withClockAndReset(clk, !rstn){ Module(new Foo) } - - foo.io.a := a_i - b_o := foo.io.b -} -``` - -In the example above, the `RawModule` is used to change the reset polarity -of module `SlaveSpi`. Indeed, the reset is active high by default in Chisel -modules, then using `withClockAndReset(clock, !rstn)` we can use an active low -reset in entire design. - -The clock is just wired as it, but if needed, `RawModule` can be used in -conjunction with `BlackBox` to connect a differential clock input for example. diff --git a/docs/src/wiki-deprecated/muxes-and-input-selection.md b/docs/src/wiki-deprecated/muxes-and-input-selection.md deleted file mode 100644 index fd7b7e7f..00000000 --- a/docs/src/wiki-deprecated/muxes-and-input-selection.md +++ /dev/null @@ -1,56 +0,0 @@ ---- -layout: docs -title: "Muxes and Input Selection" -section: "chisel3" ---- -Selecting inputs is very useful in hardware description, and therefore Chisel provides several built-in generic input-selection implementations. -### Mux -The first one is `Mux`. This is a 2-input selector. Unlike the `Mux2` example which was presented previously, the built-in `Mux` allows -the inputs (`in0` and `in1`) to be any datatype as long as they are the same subclass of `Data`. - -by using the functional module creation feature presented in the previous section, we can create multi-input selector in a simple way: - -```scala -Mux(c1, a, Mux(c2, b, Mux(..., default))) -``` - -### MuxCase -However, this is not necessary since Chisel also provides the built-in `MuxCase`, which implements that exact feature. -`MuxCase` is an n-way `Mux`, which can be used as follows: - -```scala -MuxCase(default, Array(c1 -> a, c2 -> b, ...)) -``` - -Where each selection dependency is represented as a tuple in a Scala -array [ condition -> selected_input_port ]. - -### MuxLookup -Chisel also provides `MuxLookup` which is an n-way indexed multiplexer: - -```scala -MuxLookup(idx, default, - Array(0.U -> a, 1.U -> b, ...)) -``` - -This is the same as a `MuxCase`, where the conditions are all index based selection: - -```scala -MuxCase(default, - Array((idx === 0.U) -> a, - (idx === 1.U) -> b, ...)) -``` - -Note that the conditions/cases/selectors (eg. c1, c2) must be in parentheses. - -### Mux1H -Another ```Mux``` utility is ```Mux1H``` that takes a sequence of selectors and values and returns the value associated with the one selector that is set. If zero or multiple selectors are set the behavior is undefined. For example: -```scala - val hotValue = chisel3.util.oneHotMux(Seq( - io.selector(0) -> 2.U, - io.selector(1) -> 4.U, - io.selector(2) -> 8.U, - io.selector(4) -> 11.U, - )) -``` -```oneHotMux``` whenever possible generates *Firrtl* that is readily optimizable as low depth and/or tree. This optimization is not possible when the values are of type ```FixedPoint``` or an aggregate type that contains ```FixedPoint```s and results instead as a simple ```Mux``` tree. This behavior could be sub-optimal. As ```FixedPoint``` is still *experimental* this behavior may change in the future. diff --git a/docs/src/wiki-deprecated/operators.md b/docs/src/wiki-deprecated/operators.md deleted file mode 100644 index c23e2009..00000000 --- a/docs/src/wiki-deprecated/operators.md +++ /dev/null @@ -1,63 +0,0 @@ ---- -layout: docs -title: "Operators" -section: "chisel3" ---- -### List of operators -Chisel defines a set of hardware operators: - -| Operation | Explanation | -| --------- | --------- | -| **Bitwise operators** | **Valid on:** SInt, UInt, Bool | -| `val invertedX = ~x` | Bitwise NOT | -| `val hiBits = x & "h_ffff_0000".U` | Bitwise AND | -| `val flagsOut = flagsIn \| overflow` | Bitwise OR | -| `val flagsOut = flagsIn ^ toggle` | Bitwise XOR | -| **Bitwise reductions.** | **Valid on:** SInt and UInt. Returns Bool. | -| `val allSet = x.andR` | AND reduction | -| `val anySet = x.orR` | OR reduction | -| `val parity = x.xorR` | XOR reduction | -| **Equality comparison.** | **Valid on:** SInt, UInt, and Bool. Returns Bool. | -| `val equ = x === y` | Equality | -| `val neq = x =/= y` | Inequality | -| **Shifts** | **Valid on:** SInt and UInt | -| `val twoToTheX = 1.S << x` | Logical shift left | -| `val hiBits = x >> 16.U` | Right shift (logical on UInt and arithmetic on SInt). | -| **Bitfield manipulation** | **Valid on:** SInt, UInt, and Bool. | -| `val xLSB = x(0)` | Extract single bit, LSB has index 0. | -| `val xTopNibble = x(15, 12)` | Extract bit field from end to start bit position. | -| `val usDebt = Fill(3, "hA".U)` | Replicate a bit string multiple times. | -| `val float = Cat(sign, exponent, mantissa)` | Concatenates bit fields, with first argument on left. | -| **Logical Operations** | **Valid on:** Bool -| `val sleep = !busy` | Logical NOT | -| `val hit = tagMatch && valid` | Logical AND | -| `val stall = src1busy || src2busy` | Logical OR | -| `val out = Mux(sel, inTrue, inFalse)` | Two-input mux where sel is a Bool | -| **Arithmetic operations** | **Valid on Nums:** SInt and UInt. | -| `val sum = a + b` *or* `val sum = a +% b` | Addition (without width expansion) | -| `val sum = a +& b` | Addition (with width expansion) | -| `val diff = a - b` *or* `val diff = a -% b` | Subtraction (without width expansion) | -| `val diff = a -& b` | Subtraction (with width expansion) | -| `val prod = a * b` | Multiplication | -| `val div = a / b` | Division | -| `val mod = a % b` | Modulus | -| **Arithmetic comparisons** | **Valid on Nums:** SInt and UInt. Returns Bool. | -| `val gt = a > b` | Greater than | -| `val gte = a >= b` | Greater than or equal | -| `val lt = a < b` | Less than | -| `val lte = a <= b` | Less than or equal | - ->Our choice of operator names was constrained by the Scala language. -We have to use triple equals```===``` for equality and ```=/=``` -for inequality to allow the -native Scala equals operator to remain usable. - -The Chisel operator precedence is not directly defined as part of the Chisel language. -Practically, it is determined by the evaluation order of the circuit, -which natuarally follows the [Scala operator precedence](https://docs.scala-lang.org/tour/operators.html). -If in doubt of operator precedence, use parentheses. - -> The Chisel/Scala operator precedence is similar but -not identical to precedence in Java or C. Verilog has the same operator precedence as C, but VHDL -does not. Verilog has precedence ordering for logic operations, but in VHDL -those operators have the same precedence and are evaluated from left to right. diff --git a/docs/src/wiki-deprecated/polymorphism-and-parameterization.md b/docs/src/wiki-deprecated/polymorphism-and-parameterization.md deleted file mode 100644 index c652baca..00000000 --- a/docs/src/wiki-deprecated/polymorphism-and-parameterization.md +++ /dev/null @@ -1,209 +0,0 @@ ---- -layout: docs -title: "Polymorphism and Parameterization" -section: "chisel3" ---- -_This section is advanced and can be skipped at first reading._ - -Scala is a strongly typed language and uses parameterized types to specify generic functions and classes. -In this section, we show how Chisel users can define their own reusable functions and classes using parameterized classes. - -# Parameterized Functions - -Earlier we defined `Mux2` on `Bool`, but now we show how we can define a generic multiplexer function. -We define this function as taking a boolean condition and con and alt arguments (corresponding to then and else expressions) of type `T`: - -```scala -def Mux[T <: Bits](c: Bool, con: T, alt: T): T = { ... } -``` - -where `T` is required to be a subclass of `Bits`. -Scala ensures that in each usage of `Mux`, it can find a common superclass of the actual con and alt argument types, -otherwise it causes a Scala compilation type error. -For example, - -```scala -Mux(c, UInt(10), UInt(11)) -``` - -yields a `UInt` wire because the `con` and `alt` arguments are each of type `UInt`. - - - -# Parameterized Classes - -Like parameterized functions, we can also parameterize classes to make them more reusable. -For instance, we can generalize the Filter class to use any kind of link. -We do so by parameterizing the `FilterIO` class and defining the constructor to take a single argument `gen` of type `T` as below. - -```scala -class FilterIO[T <: Data](gen: T) extends Bundle { - val x = Input(gen) - val y = Output(gen) -} -``` - -We can now define `Filter` by defining a module class that also takes a link type constructor argument and passes it through to the `FilterIO` interface constructor: - -```scala -class Filter[T <: Data](gen: T) extends Module { - val io = IO(new FilterIO(gen)) - ... -} -``` - -We can now define a `PLink`-based `Filter` as follows: - -```scala -val f = Module(new Filter(new PLink)) -``` - -A generic FIFO could be defined as follows: - -```scala -class DataBundle extends Bundle { - val a = UInt(32.W) - val b = UInt(32.W) -} - -class Fifo[T <: Data](gen: T, n: Int) extends Module { - val io = IO(new Bundle { - val enqVal = Input(Bool()) - val enqRdy = Output(Bool()) - val deqVal = Output(Bool()) - val deqRdy = Input(Bool()) - val enqDat = Input(gen) - val deqDat = Output(gen) - }) - val enqPtr = RegInit(0.asUInt(sizeof(n).W)) - val deqPtr = RegInit(0.asUInt(sizeof(n).W)) - val isFull = RegInit(false.B) - val doEnq = io.enqRdy && io.enqVal - val doDeq = io.deqRdy && io.deqVal - val isEmpty = !isFull && (enqPtr === deqPtr) - val deqPtrInc = deqPtr + 1.U - val enqPtrInc = enqPtr + 1.U - val isFullNext = Mux(doEnq && ~doDeq && (enqPtrInc === deqPtr), - true.B, Mux(doDeq && isFull, false.B, - isFull)) - enqPtr := Mux(doEnq, enqPtrInc, enqPtr) - deqPtr := Mux(doDeq, deqPtrInc, deqPtr) - isFull := isFullNext - val ram = Mem(n) - when (doEnq) { - ram(enqPtr) := io.enqDat - } - io.enqRdy := !isFull - io.deqVal := !isEmpty - ram(deqPtr) <> io.deqDat -} -``` - -An Fifo with 8 elements of type DataBundle could then be instantiated as: - -```scala -val fifo = Module(new Fifo(new DataBundle, 8)) -``` - -It is also possible to define a generic decoupled (ready/valid) interface: - -```scala -class DecoupledIO[T <: Data](data: T) extends Bundle { - val ready = Input(Bool()) - val valid = Output(Bool()) - val bits = Output(data) -} -``` - -This template can then be used to add a handshaking protocol to any -set of signals: - -```scala -class DecoupledDemo extends DecoupledIO(new DataBundle) -``` - -The FIFO interface can be now be simplified as follows: - -```scala -class Fifo[T <: Data](data: T, n: Int) extends Module { - val io = IO(new Bundle { - val enq = Flipped(new DecoupledIO(data)) - val deq = new DecoupledIO(data) - }) - ... -} -``` - -# Parametrization based on Modules - -You can also parametrize modules based on other modules rather than just types. The following is an example of a module parametrized by other modules as opposed to e.g. types. - -```scala -import chisel3.experimental.{BaseModule, RawModule} - -// Provides a more specific interface since generic Module -// provides no compile-time information on generic module's IOs. -trait MyAdder { - def in1: UInt - def in2: UInt - def out: UInt -} - -class Mod1 extends RawModule with MyAdder { - val in1 = IO(Input(UInt(8.W))) - val in2 = IO(Input(UInt(8.W))) - val out = IO(Output(UInt(8.W))) - out := in1 + in2 -} - -class Mod2 extends RawModule with MyAdder { - val in1 = IO(Input(UInt(8.W))) - val in2 = IO(Input(UInt(8.W))) - val out = IO(Output(UInt(8.W))) - out := in1 - in2 -} - -class X[T <: BaseModule with MyAdder](genT: => T) extends Module { - val io = IO(new Bundle { - val in1 = Input(UInt(8.W)) - val in2 = Input(UInt(8.W)) - val out = Output(UInt(8.W)) - }) - val subMod = Module(genT) - io.out := subMod.out - subMod.in1 := io.in1 - subMod.in2 := io.in2 -} - -println(chisel3.Driver.emitVerilog(new X(new Mod1))) -println(chisel3.Driver.emitVerilog(new X(new Mod2))) -``` diff --git a/docs/src/wiki-deprecated/ports.md b/docs/src/wiki-deprecated/ports.md deleted file mode 100644 index 251ce243..00000000 --- a/docs/src/wiki-deprecated/ports.md +++ /dev/null @@ -1,67 +0,0 @@ ---- -layout: docs -title: "Ports" -section: "chisel3" ---- -Ports are used as interfaces to hardware components. A port is simply -any `Data` object that has directions assigned to its members. - -Chisel provides port constructors to allow a direction to be added -(input or output) to an object at construction time. Primitive port -constructors wrap the type of the port in `Input` or `Output`. - -An example port declaration is as follows: -```scala -class Decoupled extends Bundle { - val ready = Output(Bool()) - val data = Input(UInt(32.W)) - val valid = Input(Bool()) -} -``` - -After defining ```Decoupled```, it becomes a new type that can be -used as needed for module interfaces or for named collections of -wires. - -By folding directions into the object declarations, Chisel is able to -provide powerful wiring constructs described later. - -## Inspecting Module ports - -(Chisel 3.2+) - -Chisel 3.2 introduced `DataMirror.modulePorts` which can be used to inspect the IOs of any Chisel module (this includes modules in both `import chisel3._` and `import Chisel._`, as well as BlackBoxes from each package). -Here is an example of how to use this API: - -```scala -import chisel3.experimental.DataMirror - -class Adder extends Module { - val a = IO(Input(UInt(8.W))) - val b = IO(Input(UInt(8.W))) - val c = IO(Output(UInt(8.W))) - c := a +& b -} - -class Test extends Module { - val adder = Module(new Adder) - // for debug only - adder.a := DontCare - adder.b := DontCare - - // Inspect ports of adder - // Prints something like this - /** - * Found port clock: Clock(IO clock in Adder) - * Found port reset: Bool(IO reset in Adder) - * Found port a: UInt<8>(IO a in Adder) - * Found port b: UInt<8>(IO b in Adder) - * Found port c: UInt<8>(IO c in Adder) - */ - DataMirror.modulePorts(adder).foreach { case (name, port) => { - println(s"Found port $name: $port") - }} -} - -chisel3.Driver.execute(Array[String](), () => new Test) -``` diff --git a/docs/src/wiki-deprecated/printing.md b/docs/src/wiki-deprecated/printing.md deleted file mode 100644 index 36dcfaae..00000000 --- a/docs/src/wiki-deprecated/printing.md +++ /dev/null @@ -1,130 +0,0 @@ ---- -layout: docs -title: "Printing" -section: "chisel3" ---- -Chisel provides the `printf` function for debugging purposes. It comes in two flavors: - -* [Scala-style](#scala-style) -* [C-style](#c-style) - -### Scala-style - -Chisel also supports printf in a style similar to [Scala's String Interpolation](http://docs.scala-lang.org/overviews/core/string-interpolation.html). Chisel provides a custom string interpolator `p` which can be used as follows: - -```scala -val myUInt = 33.U -printf(p"myUInt = $myUInt") // myUInt = 33 -``` - -Note that when concatenating `p"..."` strings, you need to start with a `p"..."` string: - -```scala -// Does not interpolate the second string -val myUInt = 33.U -printf("my normal string" + p"myUInt = $myUInt") -``` - -#### Simple formatting - -Other formats are available as follows: - -```scala -// Hexadecimal -printf(p"myUInt = 0x${Hexadecimal(myUInt)}") // myUInt = 0x21 -// Binary -printf(p"myUInt = ${Binary(myUInt)}") // myUInt = 100001 -// Character -printf(p"myUInt = ${Character(myUInt)}") // myUInt = ! -``` - -We recognize that the format specifiers are verbose, so we are working on a more concise syntax. - -#### Aggregate data-types - -Chisel provides default custom "pretty-printing" for Vecs and Bundles. The default printing of a Vec is similar to printing a Seq or List in Scala while printing a Bundle is similar to printing a Scala Map. - -```scala -val myVec = Vec(5.U, 10.U, 13.U) -printf(p"myVec = $myVec") // myVec = Vec(5, 10, 13) - -val myBundle = Wire(new Bundle { - val foo = UInt() - val bar = UInt() -}) -myBundle.foo := 3.U -myBundle.bar := 11.U -printf(p"myBundle = $myBundle") // myBundle = Bundle(a -> 3, b -> 11) -``` - -#### Custom Printing - -Chisel also provides the ability to specify _custom_ printing for user-defined Bundles. - -```scala -class Message extends Bundle { - val valid = Bool() - val addr = UInt(32.W) - val length = UInt(4.W) - val data = UInt(64.W) - override def toPrintable: Printable = { - val char = Mux(valid, 'v'.U, '-'.U) - p"Message:\n" + - p" valid : ${Character(char)}\n" + - p" addr : 0x${Hexadecimal(addr)}\n" + - p" length : $length\n" + - p" data : 0x${Hexadecimal(data)}\n" - } -} - -val myMessage = Wire(new Message) -myMessage.valid := true.B -myMessage.addr := "h1234".U -myMessage.length := 10.U -myMessage.data := "hdeadbeef".U - -printf(p"$myMessage") -``` - -Which prints the following: - -``` -Message: - valid : v - addr : 0x00001234 - length : 10 - data : 0x00000000deadbeef -``` - -Notice the use of `+` between `p` interpolated "strings". The results of `p` interpolation can be concatenated by using the `+` operator. For more information, please see the documentation - -### C-Style - -Chisel provides `printf` in a similar style to its C namesake. It accepts a double-quoted format string and a variable number of arguments which will then be printed on rising clock edges. Chisel supports the following format specifiers: - -| Format Specifier | Meaning | -| :-----: | :-----: | -| `%d` | decimal number | -| `%x` | hexadecimal number | -| `%b` | binary number | -| `%c` | 8-bit ASCII character | -| `%%` | literal percent | - -It also supports a small set of escape characters: - -| Escape Character | Meaning | -| :-----: | :-----: | -| `\n` | newline | -| `\t` | tab | -| `\"` | literal double quote | -| `\'` | literal single quote | -| `\\` | literal backslash | - -Note that single quotes do not require escaping, but are legal to escape. - -Thus printf can be used in a way very similar to how it is used in C: - -```scala -val myUInt = 32.U -printf("myUInt = %d", myUInt) // myUInt = 32 -``` diff --git a/docs/src/wiki-deprecated/reset.md b/docs/src/wiki-deprecated/reset.md deleted file mode 100644 index f5e4a24a..00000000 --- a/docs/src/wiki-deprecated/reset.md +++ /dev/null @@ -1,177 +0,0 @@ ---- -layout: docs -title: "Reset" -section: "chisel3" ---- - -```scala mdoc:invisible -import chisel3._ - -class Submodule extends Module -``` - -As of Chisel 3.2.0, Chisel 3 supports both synchronous and asynchronous reset, -meaning that it can natively emit both synchronous and asynchronously reset registers. - -The type of register that is emitted is based on the type of the reset signal associated -with the register. - -There are three types of reset that implement a common trait `Reset`: -* `Bool` - constructed with `Bool()`. Also known as "synchronous reset". -* `AsyncReset` - constructed with `AsyncReset()`. Also known as "asynchronous reset". -* `Reset` - constructed with `Reset()`. Also known as "abstract reset". - -For implementation reasons, the concrete Scala type is `ResetType`. Stylistically we avoid `ResetType`, instead using the common trait `Reset`. - -Registers with reset signals of type `Bool` are emitted as synchronous reset flops. -Registers with reset signals of type `AsyncReset` are emitted as asynchronouly reset flops. -Registers with reset signals of type `Reset` will have their reset type _inferred_ during FIRRTL compilation. - -### Reset Inference - -FIRRTL will infer a concrete type for any signals of type abstract `Reset`. -The rules are as follows: -1. An abstract `Reset` with only signals of type `AsyncReset`, abstract `Reset`, and `DontCare` -in both its fan-in and fan-out will infer to be of type `AsyncReset` -2. An abstract `Reset` with signals of both types `Bool` and `AsyncReset` in its fan-in and fan-out -is an error. -3. Otherwise, an abstract `Reset` will infer to type `Bool`. - -You can think about (3) as the mirror of (1) replacing `AsyncReset` with `Bool` with the additional -rule that abstract `Reset`s with neither `AsyncReset` nor `Bool` in their fan-in and fan-out will -default to type `Bool`. -This "default" case is uncommon and implies that reset signal is ultimately driven by a `DontCare`. - -### Implicit Reset - -A `Module`'s `reset` is of type abstract `Reset`. -Prior to Chisel 3.2.0, the type of this field was `Bool`. -For backwards compatability, if the top-level module has an implicit reset, its type will default to `Bool`. - -#### Setting Implicit Reset Type - -_New in Chisel 3.3.0_ - -If you would like to set the reset type from within a Module (including the top-level `Module`), -rather than relying on _Reset Inference_, you can mixin one of the following traits: -* `RequireSyncReset` - sets the type of `reset` to `Bool` -* `RequireAsyncReset` - sets the type of `reset` to `AsyncReset` - -For example: - -```scala mdoc:silent -class MyAlwaysSyncResetModule extends Module with RequireSyncReset { - val mySyncResetReg = RegInit(false.B) // reset is of type Bool -} -``` - -```scala mdoc:silent -class MyAlwaysAsyncResetModule extends Module with RequireAsyncReset { - val myAsyncResetReg = RegInit(false.B) // reset is of type AsyncReset -} -``` - -**Note:** This sets the concrete type, but the Scala type will remain `Reset`, so casting may still be necessary. -This comes up most often when using a reset of type `Bool` in logic. - - -### Reset-Agnostic Code - -The purpose of abstract `Reset` is to make it possible to design hardware that is agnostic to the -reset discipline used. -This enables code reuse for utilities and designs where the reset discipline does not matter to -the functionality of the block. - -Consider the two example modules below which are agnostic to the type of reset used within them: - -```scala mdoc:silent -class ResetAgnosticModule extends Module { - val io = IO(new Bundle { - val out = UInt(4.W) - }) - val resetAgnosticReg = RegInit(0.U(4.W)) - resetAgnosticReg := resetAgnosticReg + 1.U - io.out := resetAgnosticReg -} - -class ResetAgnosticRawModule extends RawModule { - val clk = IO(Input(Clock())) - val rst = IO(Input(Reset())) - val out = IO(Output(UInt(8.W))) - - val resetAgnosticReg = withClockAndReset(clk, rst)(RegInit(0.U(8.W))) - resetAgnosticReg := resetAgnosticReg + 1.U - out := resetAgnosticReg -} -``` - -These modules can be used in both synchronous and asynchronous reset domains. -Their reset types will be inferred based on the context within which they are used. - -### Forcing Reset Type - -You can set the type of a Module's implicit reset as described [above](#setting-implicit-reset-type). - -You can also cast to force the concrete type of reset. -* `.asBool` will reinterpret a `Reset` as `Bool` -* `.asAsyncReset` will reinterpret a `Reset` as `AsyncReset`. - -You can then use `withReset` to use a cast reset as the implicit reset. -See ["Multiple Clock Domains"](../explanations/multi-clock) for more information about `withReset`. - - -The following will make `myReg` as well as both `resetAgnosticReg`s synchronously reset: - -```scala mdoc:silent -class ForcedSyncReset extends Module { - // withReset's argument becomes the implicit reset in its scope - withReset (reset.asBool) { - val myReg = RegInit(0.U) - val myModule = Module(new ResetAgnosticModule) - - // RawModules do not have implicit resets so withReset has no effect - val myRawModule = Module(new ResetAgnosticRawModule) - // We must drive the reset port manually - myRawModule.rst := Module.reset // Module.reset grabs the current implicit reset - } -} -``` - -The following will make `myReg` as well as both `resetAgnosticReg`s asynchronously reset: - -```scala mdoc:silent -class ForcedAysncReset extends Module { - // withReset's argument becomes the implicit reset in its scope - withReset (reset.asAsyncReset){ - val myReg = RegInit(0.U) - val myModule = Module(new ResetAgnosticModule) // myModule.reset is connected implicitly - - // RawModules do not have implicit resets so withReset has no effect - val myRawModule = Module(new ResetAgnosticRawModule) - // We must drive the reset port manually - myRawModule.rst := Module.reset // Module.reset grabs the current implicit reset - } -} -``` - -**Note:** such casts (`asBool` and `asAsyncReset`) are not checked by FIRRTL. -In doing such a cast, you as the designer are effectively telling the compiler -that you know what you are doing and to force the type as cast. - -### Last-Connect Semantics - -It is **not** legal to override the reset type using last-connect semantics -unless you are overriding a `DontCare`: - -```scala mdoc:silent -class MyModule extends Module { - val resetBool = Wire(Reset()) - resetBool := DontCare - resetBool := false.B // this is fine - withReset(resetBool) { - val mySubmodule = Module(new Submodule()) - } - resetBool := true.B // this is fine - resetBool := false.B.asAsyncReset // this will error in FIRRTL -} -``` diff --git a/docs/src/wiki-deprecated/resources.md b/docs/src/wiki-deprecated/resources.md deleted file mode 100644 index 8b75be49..00000000 --- a/docs/src/wiki-deprecated/resources.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -layout: docs -title: "Resources and References" -section: "chisel3" ---- - -The *best resource* to learn about Chisel is the [**online Chisel Bootcamp**](https://mybinder.org/v2/gh/freechipsproject/chisel-bootcamp/master). This runs in your browser and assumes no prior Scala knowledge. (You may also run this locally via the [backing chisel-bootcamp GitHub repository](https://github.com/freechipsproject/chisel-bootcamp).) - -When you're ready to build your own circuits in Chisel, **we recommend starting from the [Chisel Template](https://github.com/freechipsproject/chisel-template) repository**, which provides a pre-configured project, example design, and testbench. Follow the [chisel-template readme](https://github.com/freechipsproject/chisel-template) to get started. - -The following additional resources and references may be useful: - -- [Chisel Cheatsheet](https://github.com/freechipsproject/chisel-cheatsheet/releases/latest/download/chisel_cheatsheet.pdf) -- [Digital Design With Chisel](https://github.com/schoeberl/chisel-book) diff --git a/docs/src/wiki-deprecated/sbt-subproject.md b/docs/src/wiki-deprecated/sbt-subproject.md deleted file mode 100644 index 77273800..00000000 --- a/docs/src/wiki-deprecated/sbt-subproject.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -layout: docs -title: "Developers" -section: "chisel3" ---- - -## Chisel as an sbt subproject - -In order to use the constructs defined in the Chisel3 library, those definitions must be made available to the Scala -compiler at the time a project dependent on them is compiled. -For sbt-based builds there are fundamentally two ways to do this: -* provide a library dependency on the published Chisel3 jars via sbt's `libraryDependencies` setting, -* clone the Chisel3 git repository and include the source code as a subproject of a dependent project. - -The former of these two approaches is used by the chisel-tutorial project. -It is the simplest approach and assumes you do not require tight control over Chisel3 source code and are content with the -published release versions of Chisel3. - -The latter approach should be used by Chisel3 projects that require finer control over Chisel3 source code. - -It's hard to predict in advance the future requirements of a project, and it would be advantageous to be able to -switch between the two approaches relatively easily. -In order to accomplish this, we provide the `sbt-chisel-dep` plugin that allows the developer to concisely specify -Chisel3 subproject dependencies and switch between subproject and library dependency support based on the presence of -a directory (or symbolic link) in the root of the dependent project. - -The chisel-template project uses this plugin to support switching between either dependency (subproject or library). -By default, the chisel-template project does not contain a chisel3 subproject directory, and hence, uses a library dependency -on chisel3 (and related Chisel3 projects). -However, if you clone the chisel3 GitHub project from the root directory of the chisel-template project, creating a chisel3 -subdirectory, the `sbt-chisel-dep` plugin will take note of the chisel3 project subdirectory, -and provide an sbt subproject dependency in place of the library dependency. - -Checkout the [README for the `sbt-chisel-dep`](https://github.com/ucb-bar/sbt-chisel-dep) project for instructions on its usage. - -Example versions of the build.sbt and specification of the sbt-chisel-dep plugin are available from the [skeleton branch of the chisel-template repository](https://github.com/ucb-bar/chisel-template/tree/skeleton). diff --git a/docs/src/wiki-deprecated/sequential-circuits.md b/docs/src/wiki-deprecated/sequential-circuits.md deleted file mode 100644 index 10294403..00000000 --- a/docs/src/wiki-deprecated/sequential-circuits.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -layout: docs -title: "Sequential Circuits" -section: "chisel3" ---- -The simplest form of state element supported by Chisel is a positive edge-triggered register, which can be instantiated as: -```scala -val reg = RegNext(in) -``` -This circuit has an output that is a copy of the input signal `in` delayed by one clock cycle. Note that we do not have to specify the type of Reg as it will be automatically inferred from its input when instantiated in this way. In the current version of Chisel, clock and reset are global signals that are implicitly included where needed. - -Note that registers which do not specify an initial value will not change value upon toggling the reset signal. - -Using registers, we can quickly define a number of useful circuit constructs. For example, a rising-edge detector that takes a boolean signal in and outputs true when the current value is true and the previous value is false is given by: -```scala -def risingedge(x: Bool) = x && !RegNext(x) -``` -Counters are an important sequential circuit. To construct an up-counter that counts up to a maximum value, max, then wraps around back to zero (i.e., modulo max+1), we write: -```scala -def counter(max: UInt) = { - val x = RegInit(0.asUInt(max.getWidth)) - x := Mux(x === max, 0.U, x + 1.U) - x -} -``` -The counter register is created in the counter function with a reset value of 0 (with width large enough to hold max), to which the register will be initialized when the global reset for the circuit is asserted. The := assignment to x in counter wires an update combinational circuit which increments the counter value unless it hits the max at which point it wraps back to zero. Note that when x appears on the right-hand side of an assignment, its output is referenced, whereas when on the left-hand side, its input is referenced. -Counters can be used to build a number of useful sequential circuits. For example, we can build a pulse generator by outputting true when a counter reaches zero: -```scala -// Produce pulse every n cycles. -def pulse(n: UInt) = counter(n - 1.U) === 0.U -``` -A square-wave generator can then be toggled by the pulse train, toggling between true and false on each pulse: -```scala -// Flip internal state when input true. -def toggle(p: Bool) = { - val x = RegInit(false.B) - x := Mux(p, !x, x) - x -} -// Square wave of a given period. -def squareWave(period: UInt) = toggle(pulse(period/2)) -``` diff --git a/docs/src/wiki-deprecated/style.md b/docs/src/wiki-deprecated/style.md deleted file mode 100644 index c845f7b4..00000000 --- a/docs/src/wiki-deprecated/style.md +++ /dev/null @@ -1,275 +0,0 @@ -# Chisel Style Guide - -The Chisel style guide reflects the [Google Java style -guide](http://google.github.io/styleguide/javaguide.html) and the [General Public Scala style -guide](http://docs.scala-lang.org/style/). Specific rules below are to clarify -the style used for the chisel3 repo and repos related to Chisel (Firrtl). - -**Goal:** Readability and consistency are the main purposes of the style guide. -Writing your code so someone else (or yourself) can grok it later is important -to code health and quality. - -## Filenames -The source file name consists of the case-sensitive name of the top-level class -it contains, plus ".scala". - -## Packages - -Package definitions must contain the full path to the package from scala. If -you create a subpackage, it should go in a subdirectory. - - package directory.name.to.get.you.to.your.source - -As in Scala, packages follow the [Java package naming convention](https://google.github.io/styleguide/javaguide.html#s5.2.1-package-names). -Note that these guidelines call for all lowercase, no underscores. - -```scala -// Do this -package hardware.chips.topsecret.masterplan - -// Not this -package hardware.chips.veryObvious.bad_style -``` - -We also suggest you do not use chisel3 as a package, and especially do not use it -as the final (innermost) package. - -```scala -// Don't do this -package hardware.chips.newchip.superfastcomponent.chisel3 - -// This will lead to instantiating package members like so: -val module = Module(new chisel3.FastModule) - -// Which collides with the chisel namespace -import chisel3._ -``` - -## Imports -Avoid wildcard ( ._ ) imports, with the exception of chisel3._ -All other imports must call out used methods. -`import chisel3._` must be first, and separated from remaining imports with an extra blank line. - -**Reason:** This makes it clear where methods are defined. - -Any remaining imports must be listed alphabetically. - -```scala -import chisel3._ - -import the.other.thing.that.i.reference.inline -import the.other.things.that.i.reference.{ClassOne, ClassTwo} - - -val myInline = inline.MakeAnInline() -val myClassOne = new ClassOne -``` - -## Tests -Test classes are named starting with the name of the class they are testing, and -ending with "Test". -Test files must start with the name of the class you are testing and end with -"Test.scala". -Test files should reside in a subdirectory called "tests". -The tests package should be composed of the package class you are testing. - -```scala -package class.under.test.class -package tests -``` - -## Comments -We use scaladoc to automatically generate documentation from the source code. - -```scala -/** Multiple lines of ScalaDoc text are written here, - * wrapped normally... - */ -public int method(String p1) { ... } -``` - -... or in this single-line example: - -```scala -/** An especially short bit of Javadoc. */ -``` - -Write documentation as if the person reading it knows more about Scala and -Chisel than you. If you find comments in the code consider breaking them up -into seperate methods. - -## Module Classes and Instances - -Modules can take different forms in Chisel. The first form is similar to Verilog, where -you instance the module and then hook it up. In this case `Module(new MyMod())` is -returning a reference to the module. - -```scala -val myMod = Module(new MyMod()) -myMod.io <> hookUp -``` - -The second form is a more programmatic inline style with factory methods. In this case, -Queue is actually returning the part of the IO bundle representing the queue's -output. The factory method takes the input IO to the queue and an optional parameter -for depth. - -```scala -val queueOut = Queue(queueIn, depth=10) -``` - -The latter can be used for composing multiple functions into a single line. - -```scala -val queueOut = Queue( - Arbitrate.byRoundRobin( - Queue(a), // depth assumed to be 1 - Queue(b, depth=3), - Queue(c, depth=4) - ), - depth=10 -) -``` - -## Naming Conventions - -Chisel follows the [Scala Naming Conventions](http://docs.scala-lang.org/style/naming-conventions.html). -In general, Chisel code should use CamelCase for naming (ie. the first letter -of each word is capitalized except sometimes the first word). - -### Why CamelCase instead of Snake\_Case? - -The compiler inserts underscores when splitting Chisel/FIRRTL aggregate types -into Verilog types. The compiler uses underscores to preserve the original -structure of the data in the resulting Verilog. Because of the special meaning -of underscores in Chisel-generated Verilog, their use in naming is **strongly** -discouraged. - -Consider the following Chisel code: - -```scala -val msg = Wire(new Bundle { - val valid = Bool() - val addr = UInt(32) - val data = UInt(64) -}) -val msg_rec = Wire(Bool()) -``` - -Which compiles to the Verilog: - -```verilog -wire msg_valid; -wire [31:0] msg_addr; -wire [63:0] msg_data; -wire msg_rec; -``` - -The Verilog maintains the structure of the original aggregate wire `msg`. -However, because we named another variable `msg_rec`, it appears in the Verilog -as if `msg` had 4 fields instead of its actual 3! If we instead follow the -lowerCamelCase for values naming convention, the resulting Verilog makes more -sense: - -```scala -val msg = Wire(new Bundle { - val valid = Bool() - val addr = UInt(32) - val data = UInt(64) -}) -val msgRec = Wire(Bool()) -``` - -And its resulting Verilog: - -```verilog -wire msg_valid; -wire [31:0] msg_addr; -wire [63:0] msg_data; -wire msgRec; -``` - -Much better. - -### Modules and Bundles (Classes, Traits, and Objects) - -Modules are Scala classes and thus use UpperCamelCase. - -```scala -class ModuleNamingExample extends Module { - ... -} -``` - -Similarly, other classes (Chisel & Scala) should be UpperCamelCase as well. - -```scala -trait UsefulScalaUtilities { - def isEven(n: Int): Boolean = (n % 2) == 0 - def isOdd(n: Int): Boolean = !isEven(n) -} - -class MyCustomBundle extends Bundle { - ... -} -// Companion object to MyCustomBundle -object MyCustomBundle { - ... -} - -``` - -### Values and Methods - -Values and methods should use lowerCamelCase. (Unless the value is a constant.) - -```scala -val mySuperReg = Reg(init = 0.asUInt(32)) -def myImportantMethod(a: UInt): Bool = a < 23.asUInt -``` - -### Constants - -Unlike the Google Java style, constants use UpperCamelCase, which is in line -with the official [Scala Naming -Conventions](https://docs.scala-lang.org/style/naming-conventions.html). -Constants are final fields (val or object) whose contents are deeply immutable -and belong to a package object or an object. Examples: - -```scala -// Constants -object Constants { - val Number = 5 - val Names = "Ed" :: "Ann" :: Nil - val Ages = Map("Ed" -> 35, "Ann" -> 32) -} - -// Not constants -class NonConstantsInClass { - val inClass: String = "in-class" -} - -object nonConstantsInObject { - var varString = "var-string" - val mutableCollection: scala.collection.mutable.Set[String] - val mutableElements = Set(mutable) -} -``` - -### UpperCamelCase vs. lowerCamelCase - -There is more than one reasonable way to covert English prose into camel case. -We follow the convention defined in the [Google Java style -guide](https://google.github.io/styleguide/javaguide.html#s5.3-camel-case). The -potentially non-obvious rule being to treat acronymns as words for the purpose -of camel case. - -Note that the casing of the original words is almost entirely disregarded. -Example: - -Prose form | UpperCamelCase | lowerCamelCase | Incorrect -:------------- | :------------- | :------------- | :------------ -find GCD | FindGcd | findGcd | ~~findGCD~~ -state for FSM | StateForFsm | stateForFsm | ~~stateForFSM~~ -mock dut | MockDut | mockDut | ~~MockDUT~~ -FIFO Generator | FifoGenerator | fifoGenerator | ~~FIFOGenerator~~ diff --git a/docs/src/wiki-deprecated/supported-hardware.md b/docs/src/wiki-deprecated/supported-hardware.md deleted file mode 100644 index 97f82698..00000000 --- a/docs/src/wiki-deprecated/supported-hardware.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -layout: docs -title: "Supported Hardware" -section: "chisel3" ---- -While Chisel focuses on binary logic, Chisel can support analog and tri-state wires with the `Analog` type - see [Datatypes in Chisel](data-types). - -We focus on binary logic designs as they constitute the vast majority of designs in practice. Tri-state logic are poorly supported standard industry flows and require special/controlled hard macros in order to be done. diff --git a/docs/src/wiki-deprecated/test-coverage.md b/docs/src/wiki-deprecated/test-coverage.md deleted file mode 100644 index a3a622a2..00000000 --- a/docs/src/wiki-deprecated/test-coverage.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -layout: docs -title: "Test Coverage" -section: "chisel3" ---- - -## Test Coverage Setup - -Chisel's sbt build instructions contain the requisite plug-in (sbt-scoverage) for generating test coverage information. Please see the [sbt-scoverage web page](https://github.com/scoverage/sbt-scoverage) for details on the plug-in. -The tests themselves are found in `src/test/scala`. - -## Generating A Test Coverage Report - -Use the following sequence of sbt commands to generate a test coverage report: -``` -sbt clean coverage test -sbt coverageReport -``` -The coverage reports should be found in `target/scala-x.yy/scoverage-report/{scoverage.xml,index.html}` where `x.yy` corresponds to the version of Scala used to compile Firrtl and the tests. -`scoverage.xml` is useful if you want to analyze the results programmatically. -`index.html` is designed for navigation with a web browser, allowing one to drill down to invidual statements covered (or not) by the tests. diff --git a/docs/src/wiki-deprecated/troubleshooting.md b/docs/src/wiki-deprecated/troubleshooting.md deleted file mode 100644 index 333adec4..00000000 --- a/docs/src/wiki-deprecated/troubleshooting.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -layout: docs -title: "Troubleshooting" -section: "chisel3" ---- -This page is a starting point for recording common and not so common problems in developing with Chisel3. In particular, those situations where there is a work around that will keep you going. - -### `type mismatch` specifying width/value of a `UInt`/`SInt` - -*I have some old code that used to work correctly in chisel2 (and still does if I use the `import Chisel._` compatibility layer) -but causes a `type mismatch` error in straight chisel3:* - -```scala -class TestBlock extends Module { - val io = IO(new Bundle { - val output = Output(UInt(width=3)) - }) -} -``` -*produces* -```bash -type mismatch; -[error] found : Int(3) -[error] required: chisel3.internal.firrtl.Width -[error] val output = Output(UInt(width=3)) -``` - -The single argument, multi-function object/constructors from chisel2 have been removed from chisel3. -It was felt these were too prone to error and made it difficult to diagnose error conditions in chisel3 code. - -In chisel3, the single argument to the `UInt`/`SInt` object/constructor specifies the *width* and must be a `Width` type. -Although there are no automatic conversions from `Int` to `Width`, an `Int` may be converted to a `Width` by applying the `W` method to an `Int`. -In chisel3, the above code becomes: -```scala -class TestBlock extends Module { - val io = IO(new Bundle { - val output = Output(UInt(3.W)) - }) -} -``` -`UInt`/`SInt` literals may be created from an `Int` with the application of either the `U` or `S` method. - -```scala -UInt(42) -``` -in chisel2, becomes -```scala -42.U -``` -in chisel3 - -A literal with a specific width is created by calling the `U` or `S` method with a `W` argument. -Use: -```scala -1.S(8.W) -``` -to create an 8-bit wide (signed) literal with value 1. diff --git a/docs/src/wiki-deprecated/unconnected-wires.md b/docs/src/wiki-deprecated/unconnected-wires.md deleted file mode 100644 index 1fa12e59..00000000 --- a/docs/src/wiki-deprecated/unconnected-wires.md +++ /dev/null @@ -1,112 +0,0 @@ ---- -layout: docs -title: "Unconnected Wires" -section: "chisel3" ---- -The Invalidate API [(#645)](https://github.com/freechipsproject/chisel3/pull/645) adds support to chisel -for reporting unconnected wires as errors. - -Prior to this pull request, chisel automatically generated a firrtl `is invalid` for `Module IO()`, and each `Wire()` definition. -This made it difficult to detect cases where output signals were never driven. -Chisel now supports a `DontCare` element, which may be connected to an output signal, indicating that that signal is intentionally not driven. -Unless a signal is driven by hardware or connected to a `DontCare`, Firrtl will complain with a "not fully initialized" error. - -### API - -Output signals may be connected to DontCare, generating a `is invalid` when the corresponding firrtl is emitted. -```scala -io.out.debug := true.B -io.out.debugOption := DontCare -``` -This indicates that the signal `io.out.debugOption` is intentionally not driven and firrtl should not issue a "not fully initialized" -error for this signal. - -This can be applied to aggregates as well as individual signals: -```scala -{ - ... - val nElements = 5 - val io = IO(new Bundle { - val outs = Output(Vec(nElements, Bool())) - }) - io.outs <> DontCare - ... -} - -class TrivialInterface extends Bundle { - val in = Input(Bool()) - val out = Output(Bool()) -} - -{ - ... - val io = IO(new TrivialInterface) - io <> DontCare - ... -} -``` - -This feature is controlled by `CompileOptions.explicitInvalidate` and is set to `false` in `NotStrict` (Chisel2 compatibility mode), -and `true` in `Strict` mode. - -You can selectively enable this for Chisel2 compatibility mode by providing your own explicit `compileOptions`, -either for a group of Modules (via inheritance): -```scala -abstract class ExplicitInvalidateModule extends Module()(chisel3.core.ExplicitCompileOptions.NotStrict.copy(explicitInvalidate = true)) -``` -or on a per-Module basis: -```scala -class MyModule extends Module { - override val compileOptions = chisel3.core.ExplicitCompileOptions.NotStrict.copy(explicitInvalidate = true) - ... -} -``` - -Or conversely, disable this stricter checking (which is now the default in pure chisel3): -```scala -abstract class ImplicitInvalidateModule extends Module()(chisel3.core.ExplicitCompileOptions.Strict.copy(explicitInvalidate = false)) -``` -or on a per-Module basis: -```scala -class MyModule extends Module { - override val compileOptions = chisel3.core.ExplicitCompileOptions.Strict.copy(explicitInvalidate = false) - ... -} -``` - -Please see the corresponding [API tests](https://github.com/freechipsproject/chisel3/blob/master/src/test/scala/chiselTests/InvalidateAPISpec.scala) -for examples. - -### Determining the unconnected element - -I have an interface with 42 wires. -Which one of them is unconnected? - -The firrtl error message should contain something like: -```bash -firrtl.passes.CheckInitialization$RefNotInitializedException: @[:@6.4] : [module Router] Reference io is not fully initialized. - @[Decoupled.scala 38:19:@48.12] : node _GEN_23 = mux(and(UInt<1>("h1"), eq(UInt<2>("h3"), _T_84)), _GEN_2, VOID) @[Decoupled.scala 38:19:@48.12] - @[Router.scala 78:30:@44.10] : node _GEN_36 = mux(_GEN_0.ready, _GEN_23, VOID) @[Router.scala 78:30:@44.10] - @[Router.scala 75:26:@39.8] : node _GEN_54 = mux(io.in.valid, _GEN_36, VOID) @[Router.scala 75:26:@39.8] - @[Router.scala 70:50:@27.6] : node _GEN_76 = mux(io.load_routing_table_request.valid, VOID, _GEN_54) @[Router.scala 70:50:@27.6] - @[Router.scala 65:85:@19.4] : node _GEN_102 = mux(_T_62, VOID, _GEN_76) @[Router.scala 65:85:@19.4] - : io.outs[3].bits.body <= _GEN_102 -``` -The first line is the initial error report. -Successive lines, indented and beginning with source line information indicate connections involving the problematic signal. -Unfortunately, if these are `when` conditions involving muxes, they may be difficult to decipher. -The last line of the group, indented and beginning with a `:` should indicate the uninitialized signal component. -This example (from the [Router tutorial](https://github.com/ucb-bar/chisel-tutorial/blob/release/src/main/scala/examples/Router.scala)) -was produced when the output queue bits were not initialized. -The old code was: -```scala - io.outs.foreach { out => out.noenq() } -``` -which initialized the queue's `valid` bit, but did not initialize the actual output values. -The fix was: -```scala - io.outs.foreach { out => - out.bits := 0.U.asTypeOf(out.bits) - out.noenq() - } -``` diff --git a/docs/src/wiki-deprecated/width-inference.md b/docs/src/wiki-deprecated/width-inference.md deleted file mode 100644 index 60f9d519..00000000 --- a/docs/src/wiki-deprecated/width-inference.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -layout: docs -title: "Width Inference" -section: "chisel3" ---- -Chisel provides bit width inference to reduce design effort. Users are encouraged to manually specify widths of ports and registers to prevent any surprises, but otherwise unspecified widths will be inferred by the Firrtl compiler. - -For all circuit components declared with unspecified widths, the FIRRTL compiler will infer the minimum possible width that maintains the legality of all its incoming connections. Implicit here is that inference is done in a right to left fashion in the sense of an assignment statement in chisel, i.e. from the left hand side from the right hand side. If a component has no incoming connections, and the width is unspecified, then an error is thrown to indicate that the width could not be inferred. - -For module input ports with unspecified widths, the inferred width is the minimum possible width that maintains the legality of all incoming connections to all instantiations of the module. -The width of a ground-typed multiplexor expression is the maximum of its two corresponding input widths. For multiplexing aggregate-typed expressions, the resulting widths of each leaf subelement is the maximum of its corresponding two input leaf subelement widths. -The width of a conditionally valid expression is the width of its input expression. For the full formal description see the [Firrtl Spec](https://github.com/freechipsproject/firrtl/blob/master/spec/spec.pdf). - -Hardware operators have output widths as defined by the following set of rules: - -| operation | bit width | -| --------- | --------- | -| `z = x + y` *or* `z = x +% y` | `w(z) = max(w(x), w(y))` | -| `z = x +& y` | `w(z) = max(w(x), w(y)) + 1` | -| `z = x - y` *or* `z = x -% y` | `w(z) = max(w(x), w(y))` | -| `z = x -& y` | `w(z) = max(w(x), w(y)) + 1` | -| `z = x & y` | `w(z) = max(w(x), w(y))` | -| `z = Mux(c, x, y)` | `w(z) = max(w(x), w(y))` | -| `z = w * y` | `w(z) = w(x) + w(y)` | -| `z = x << n` | `w(z) = w(x) + maxNum(n)` | -| `z = x >> n` | `w(z) = w(x) - minNum(n)` | -| `z = Cat(x, y)` | `w(z) = w(x) + w(y)` | -| `z = Fill(n, x)` | `w(z) = w(x) * maxNum(n)` | - ->where for instance `w(z)` is the bit width of wire `z`, and the `&` -rule applies to all bitwise logical operations. - -Given a path of connections that begins with an unspecified width element (most commonly a top-level input), then the compiler will throw an exception indicating a certain width was uninferrable. - -A common "gotcha" comes from truncating addition and subtraction with the operators `+` and `-`. Users who want the result to maintain the full, expanded precision of the addition or subtraction should use the expanding operators `+&` and `-&`. - -> The default truncating operation comes from Chisel's history as a microprocessor design language. -- cgit v1.2.3 From 03ec2156988ddef35272365fb86415511eafb4e2 Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Thu, 18 Mar 2021 23:30:05 -0700 Subject: Update the FAQ and add doc on versioning (#1827) * Update the FAQ and add doc on versioning * Update modules.md Co-authored-by: Megan Wachs --- docs/src/appendix/appendix.md | 1 + docs/src/appendix/versioning.md | 35 ++++++++++++++++ docs/src/explanations/modules.md | 4 +- docs/src/resources/faqs.md | 86 +++++----------------------------------- 4 files changed, 48 insertions(+), 78 deletions(-) create mode 100644 docs/src/appendix/versioning.md (limited to 'docs') diff --git a/docs/src/appendix/appendix.md b/docs/src/appendix/appendix.md index 48106fe4..0efedbfe 100644 --- a/docs/src/appendix/appendix.md +++ b/docs/src/appendix/appendix.md @@ -11,3 +11,4 @@ This section covers some less-common Chisel topics. * [Differences between Chisel3 and Chisel2](chisel3-vs-chisel2) * [Experimental Features](experimental-features) * [Upgrading from Scala 2.11](upgrading-from-scala-2-11) +* [Versioning](versioning) diff --git a/docs/src/appendix/versioning.md b/docs/src/appendix/versioning.md new file mode 100644 index 00000000..8c5ef91c --- /dev/null +++ b/docs/src/appendix/versioning.md @@ -0,0 +1,35 @@ +--- +layout: docs +title: "Versioning" +section: "chisel3" +--- + +# Chisel Project Versioning + +Chisel and related projects follow a versioning scheme similar to [PVP](https://pvp.haskell.org/). +Project versions are of the form `A.B.C` where `A.B` specifies the _Major_ version and `C` specifies the _Minor_ version. +Projects maintain _binary compatibility_ between minor versions of the same major version. +For example, a project compiled against Chisel3 version 3.4.0 can be used with Chisel3 version 3.4.2 or 3.4.15 without recompilation. + +# Compatible Versions + +Historically, due to a mistake in versioning with chisel-iotesters as well as some projects originating later than others, +the compatible versions of Chisel-related projects has not been obvious. +We are taking steps to improve the situation by bringing the major versions more in line (the `B` part in `A.B.C`), +but the inconsistencies remain in previously published versions. + +Please use the following table to determine which versions of the related projects are compatible. +In particular, versions of projects in this table were compiled against the version of any dependencies listed in the same row. +For example, `chisel-iotesters` version 1.4 was compiled against `chisel3` version 3.3. + +| chisel3 | chiseltest | chisel-iotesters | firrtl | treadle | diagrammer | firrtl-interpreter2 | +| ------- | ---------- | ---------------- | ------ | ------- | ---------- | ----- | +| 3.4 | 0.3 | 1.5 | 1.4 | 1.3 | 1.3 | 1.4 | +| 3.3 | 0.2 | 1.4 | 1.3 | 1.2 | 1.2 | 1.3 | +| 3.2 | 0.11 | 1.3 | 1.2 | 1.1 | 1.1 | 1.2 | +| 3.1 | - | 1.2 | 1.1 | 1.0 | 1.0 | 1.1 | +| 3.0 | - | 1.1 | 1.0 | -3 | - | 1.0 | + +1 chiseltest 0.1 was published under artifact name [chisel-testers2](https://search.maven.org/search?q=a:chisel-testers2_2.12) (0.2 was published under both artifact names) +2 Replaced by Treadle, in maintenance mode only since version 1.1 +3 Treadle was preceded by the firrtl-interpreter diff --git a/docs/src/explanations/modules.md b/docs/src/explanations/modules.md index 32cbff2e..f82a14d6 100644 --- a/docs/src/explanations/modules.md +++ b/docs/src/explanations/modules.md @@ -119,8 +119,8 @@ class Foo extends Module { class FooWrapper extends RawModule { val a_i = IO(Input(Bool())) val b_o = IO(Output(Bool())) - val clk = Input(Clock()) - val rstn = Input(Bool()) + val clk = IO(Input(Clock())) + val rstn = IO(Input(Bool())) val foo = withClockAndReset(clk, !rstn){ Module(new Foo) } diff --git a/docs/src/resources/faqs.md b/docs/src/resources/faqs.md index debdfcbe..feefa4d0 100644 --- a/docs/src/resources/faqs.md +++ b/docs/src/resources/faqs.md @@ -8,8 +8,8 @@ section: "chisel3" * [Where should I start if I want to learn Chisel?](#where-should-i-start-if-i-want-to-learn-chisel) * [How do I ... in Chisel?](#how-do-i-do--eg-like-that-in-verilog-in-chisel) +* [What versions of the various projects work together?](#what-versions) * [How can I contribute to Chisel?](#how-can-i-contribute-to-chisel) -* [What is the difference between release and master branches?](#what-is-the-difference-between-release-and-master-branches) * [Why DecoupledIO instead of ReadyValidIO?](#why-decoupledio-instead-of-readyvalidio) * [Why do I have to wrap module instantiations in `Module(...)`?](#why-do-i-have-to-wrap-module-instantiations-in-module) * [Why Chisel?](#why-chisel) @@ -28,42 +28,13 @@ We recommend the [Chisel Bootcamp](https://github.com/freechipsproject/chisel-bo See the [cookbooks](../cookbooks/cookbook). -### How can I contribute to Chisel? - -A good to place to start is to fill out the [How Can I Contribute Form](https://docs.google.com/forms/d/e/1FAIpQLSfwTTY8GkfSZ2sU2T2mNpfNMpIM70GlXOrjqiHoC9ZBvwn_CA/viewform). - -### What is the difference between release and master branches? - -We have two main branches for each main Chisel project: - -- `master` -- `release` - -`master` is the main development branch and it is updated frequently (often several times a day). -Although we endeavour to keep the `master` branches in sync, they may drift out of sync for a day or two. -We do not publish the `master` branches. -If you wish to use them, you need to clone the GitHub repositories and use `sbt publishLocal` to make them available on your local machine. +### What versions of the various projects work together? -The `release` branches are updated less often (currently bi-weekly) and we try to guarantee they are in sync. -We publish these to Sonatype/Maven on a bi-weekly basis. +See [Chisel Project Versioning](../appendix/versioning). -In general, you can not mix `release` and `master` branches and assume they will work. - -The default branches for the user-facing repositories (chisel-template and chisel-tutorial) are the `release` branches - these should always *just work* for new users as they use the `release` branches of chisel projects. - -If you want to use something more current than the `release` branch, you should `git checkout master` for all the chisel repos you intend to use, then `sbt publishLocal` them in this order: - -- firrtl -- firrtl-interpreter -- chisel3 -- chisel-testers - -Then, if you're working with the user-facing repositories: - -- chisel-tutorial -- chisel-template +### How can I contribute to Chisel? -Since this is a substantial amount of work (with no guarantee of success), unless you are actively involved in Chisel development, we encourage you to stick with the `release` branches and their respective dependencies. +Check out the [Contributor Documentation](https://github.com/chipsalliance/chisel3#contributor-documentation) in the chisel3 repository. ### Why DecoupledIO instead of ReadyValidIO? @@ -80,48 +51,11 @@ Chisel Modules are written by defining a [Scala class](http://docs.scala-lang.or ### Why Chisel? -Borrowed from [Chisel Motivation](../explanations/motivation) - ->We were motivated to develop a new hardware language by years of -struggle with existing hardware description languages in our research -projects and hardware design courses. _Verilog_ and _VHDL_ were developed -as hardware _simulation_ languages, and only later did they become -a basis for hardware _synthesis_. Much of the semantics of these -languages are not appropriate for hardware synthesis and, in fact, -many constructs are simply not synthesizable. Other constructs are -non-intuitive in how they map to hardware implementations, or their -use can accidently lead to highly inefficient hardware structures. -While it is possible to use a subset of these languages and still get -acceptable results, they nonetheless present a cluttered and confusing -specification model, particularly in an instructional setting. - ->However, our strongest motivation for developing a new hardware -language is our desire to change the way that electronic system design -takes place. We believe that it is important to not only teach -students how to design circuits, but also to teach them how to design -*circuit generators* ---programs that automatically generate -designs from a high-level set of design parameters and constraints. -Through circuit generators, we hope to leverage the hard work of -design experts and raise the level of design abstraction for everyone. -To express flexible and scalable circuit construction, circuit -generators must employ sophisticated programming techniques to make -decisions concerning how to best customize their output circuits -according to high-level parameter values and constraints. While -Verilog and VHDL include some primitive constructs for programmatic -circuit generation, they lack the powerful facilities present in -modern programming languages, such as object-oriented programming, -type inference, support for functional programming, and reflection. - ->Instead of building a new hardware design language from scratch, we -chose to embed hardware construction primitives within an existing -language. We picked Scala not only because it includes the -programming features we feel are important for building circuit -generators, but because it was specifically developed as a base for -domain-specific languages. +Please see [Chisel Motivation](../explanations/motivation) ### Does Chisel support X and Z logic values -Chisel does not directly support Verilog logic values ```x``` *unknown* and ```z``` *high-impedance*. There are a number of reasons to want to avoid these values. See:[The Dangers of Living With An X](http://infocenter.arm.com/help/topic/com.arm.doc.arp0009a/Verilog_X_Bugs.pdf) and [Malicious LUT: A stealthy FPGA Trojan injected and triggered by the design flow](http://ieeexplore.ieee.org/document/7827620/). Chisel has it's own eco-system of unit and functional testers that limit the need for ```x``` and ```z``` and their omission simplify language implementation, design, and testing. The circuits created by chisel do not preclude developers from using ```x``` and ```z``` in downstream toolchains as they see fit. +Chisel does not directly support Verilog logic values ```x``` *unknown* and ```z``` *high-impedance*. There are a number of reasons to want to avoid these values. See:[The Dangers of Living With An X](http://infocenter.arm.com/help/topic/com.arm.doc.arp0009a/Verilog_X_Bugs.pdf) and [Malicious LUT: A stealthy FPGA Trojan injected and triggered by the design flow](http://ieeexplore.ieee.org/document/7827620/). Chisel has its own eco-system of unit and functional testers that limit the need for ```x``` and ```z``` and their omission simplify language implementation, design, and testing. The circuits created by chisel do not preclude developers from using ```x``` and ```z``` in downstream toolchains as they see fit. ### Get me Verilog I wrote a module and I want to see the Verilog; what do I do? @@ -213,7 +147,7 @@ ChiselStage.emitVerilog(new HelloWorld()) ### Get me FIRRTL -If for some reason you don't want the Verilog (e.g. maybe you want to run some custom transformations before exporting to Verilog), then use something along these lines (replace Multiplier with your module): +If for some reason you don't want the Verilog (e.g. maybe you want to run some custom transformations before exporting to Verilog), then use something along these lines: ```scala package intro @@ -263,8 +197,8 @@ res3: String = ... ### Why doesn't Chisel tell me which wires aren't connected? -As of commit [c313e13](https://github.com/freechipsproject/chisel3/commit/c313e137d4e562ef20195312501840ceab8cbc6a) it can! -Read more at [Unconnected Wires](../explanations/unconnected-wires) for details. +As long as your code uses `import chisel3._` (and not `import Chisel._`), it does! +See [Unconnected Wires](../explanations/unconnected-wires) for details. ### What does `Reference ... is not fully initialized.` mean? -- cgit v1.2.3 From a54d37d2864d86f6374037c49c81901a613275c5 Mon Sep 17 00:00:00 2001 From: Kalamár Ödön Date: Wed, 31 Mar 2021 20:15:38 +0200 Subject: Fix formatting issue of links (#1844) --- docs/src/appendix/experimental-features.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'docs') diff --git a/docs/src/appendix/experimental-features.md b/docs/src/appendix/experimental-features.md index 0e3f50c8..c989ec97 100644 --- a/docs/src/appendix/experimental-features.md +++ b/docs/src/appendix/experimental-features.md @@ -6,11 +6,11 @@ section: "chisel3" Chisel has a number of new features that are worth checking out. This page is an informal list of these features and projects. -[FixedPoint](#fixed-point) -[Module Variants](#module-variants) -[Module Variants](#bundle-literals) -[Interval Type](#interval-type) -[Loading Memories in Simulation](#loading-memories) +- [FixedPoint](#fixed-point) +- [Module Variants](#module-variants) +- [Module Variants](#bundle-literals) +- [Interval Type](#interval-type) +- [Loading Memories in Simulation](#loading-memories) ### FixedPoint FixedPoint numbers are basic *Data* type along side of UInt, SInt, etc. Most common math and logic operations -- cgit v1.2.3 From e0da5ae47f3674bdd2018a672028290c927274e1 Mon Sep 17 00:00:00 2001 From: Carlos Eduardo Date: Wed, 7 Apr 2021 16:01:51 -0300 Subject: Add documentation guide about memory initialization (#1850) * Add documentation guide about memory initialization * Move information to experimental and add ref--- docs/src/appendix/experimental-features.md | 150 +++++++++++++++++++++++------ docs/src/explanations/memories.md | 15 ++- 2 files changed, 135 insertions(+), 30 deletions(-) (limited to 'docs') diff --git a/docs/src/appendix/experimental-features.md b/docs/src/appendix/experimental-features.md index c989ec97..363f7a06 100644 --- a/docs/src/appendix/experimental-features.md +++ b/docs/src/appendix/experimental-features.md @@ -10,7 +10,7 @@ Chisel has a number of new features that are worth checking out. This page is a - [Module Variants](#module-variants) - [Module Variants](#bundle-literals) - [Interval Type](#interval-type) -- [Loading Memories in Simulation](#loading-memories) +- [Loading Memories for simulation or FPGA initialization](#loading-memories) ### FixedPoint FixedPoint numbers are basic *Data* type along side of UInt, SInt, etc. Most common math and logic operations @@ -143,49 +143,142 @@ Consider a Interval with a binary point of 3: aaa.bbb | shiftLeftBinaryPoint(2) | a.aabbb | 5 | X | X | increase the precision | | shiftRighBinaryPoint(2) | aaaa.b | 1 | X | X | reduce the precision | -## Loading Memories in simulation +## Loading Memories for simulation or FPGA initialization -Chisel now supports an experimental method for annotating memories to be loaded from a text file containing -hex or binary numbers. When using verilog simulation it uses the `$readmemh` or `$readmemb` -verilog extension. The treadle simulator can also load memories using the same annotation. +Chisel supports multiple experimental methods for annotating memories to be loaded from a text file containing hex or binary data. When using verilog simulation it uses the `$readmemh` or `$readmemb` verilog extension. The treadle simulator can also load memories using the same annotation. -### How to annotate -Assuming you have a memory in a Module -```scala mdoc:invisible +### Inline initialization with external file + +Memories can be initialized by generating inline `readmemh` or `readmemb` statements in the output Verilog. + +The function `loadMemoryFromFileInline` from `chisel3.util.experimental` allows the memory to be initialized by the synthesis software from the specified file. Chisel does not validate the file contents nor its location. Both the memory initialization file and the Verilog source should be accessible for the toolchain. + +```scala mdoc:silent import chisel3._ -val memoryDepth = 8 -val memoryType = Bool() -``` -```scala -val memory = Mem(memoryDepth, memoryType) +import chisel3.util.experimental.loadMemoryFromFileInline + +class InitMemInline(memoryFile: String = "") extends Module { + val width: Int = 32 + val io = IO(new Bundle { + val enable = Input(Bool()) + val write = Input(Bool()) + val addr = Input(UInt(10.W)) + val dataIn = Input(UInt(width.W)) + val dataOut = Output(UInt(width.W)) + }) + + val mem = SyncReadMem(1024, UInt(width.W)) + // Initialize memory + if (memoryFile.trim().nonEmpty) { + loadMemoryFromFileInline(mem, memoryFile) + } + io.dataOut := DontCare + when(io.enable) { + val rdwrPort = mem(io.addr) + when (io.write) { rdwrPort := io.dataIn } + .otherwise { io.dataOut := rdwrPort } + } +} ``` -At the top of your file just add the import +The default is to use `$readmemh` (which assumes all numbers in the file are in ascii hex), +but to use ascii binary there is an optional `hexOrBinary` argument which can be set to `MemoryLoadFileType.Hex` or `MemoryLoadFileType.Binary`. You will need to add an additional import. + +By default, the inline initialization will generate the memory `readmem` statements inside an `ifndef SYNTHESIS` block, which suits ASIC workflow. + +Some synthesis tools (like Synplify and Yosys) define `SYNTHESIS` so the `readmem` statement is not read when inside this block. + +To control this, one can use the `MemoryNoSynthInit` and `MemorySynthInit` annotations from `firrtl.annotations`. The former which is the default setting when no annotation is present generates `readmem` inside the block. Using the latter, the statement are generated outside the `ifndef` block so it can be used by FPGA synthesis tools. + +Below an example for initialization suited for FPGA workflows: + ```scala mdoc:silent -import chisel3.util.experimental.loadMemoryFromFile -``` -Now just add the memory annotation using -```scala - loadMemoryFromFile(memory, "/workspace/workdir/mem1.txt") +import chisel3._ +import chisel3.util.experimental.loadMemoryFromFileInline +import chisel3.experimental.{annotate, ChiselAnnotation} +import firrtl.annotations.MemorySynthInit + +class InitMemInlineFPGA(memoryFile: String = "") extends Module { + val width: Int = 32 + val io = IO(new Bundle { + val enable = Input(Bool()) + val write = Input(Bool()) + val addr = Input(UInt(10.W)) + val dataIn = Input(UInt(width.W)) + val dataOut = Output(UInt(width.W)) + }) + + // Notice the annotation below + annotate(new ChiselAnnotation { + override def toFirrtl = + MemorySynthInit + }) + + val mem = SyncReadMem(1024, UInt(width.W)) + if (memoryFile.trim().nonEmpty) { + loadMemoryFromFileInline(mem, memoryFile) + } + io.dataOut := DontCare + when(io.enable) { + val rdwrPort = mem(io.addr) + when (io.write) { rdwrPort := io.dataIn } + .otherwise { io.dataOut := rdwrPort } + } +} ``` -The default is to use `$readmemh` (which assumes all numbers in the file are in ascii hex), -bu to use ascii binary there is an optional third argument. You will need to add an additional import. + +#### SystemVerilog Bind Initialization + +Chisel can also initialize memories by generating a SV bind module with `readmemh` or `readmemb` statements by using the function `loadMemoryFromFile` from `chisel3.util.experimental`. + ```scala mdoc:silent -import firrtl.annotations.MemoryLoadFileType +import chisel3._ +import chisel3.util.experimental.loadMemoryFromFile + +class InitMemBind(val bits: Int, val size: Int, filename: String) extends Module { + val io = IO(new Bundle { + val nia = Input(UInt(bits.W)) + val insn = Output(UInt(32.W)) + }) + + val memory = Mem(size, UInt(32.W)) + io.insn := memory(io.nia >> 2); + loadMemoryFromFile(memory, filename) +} ``` -```scala - loadMemoryFromFile(memory, "/workspace/workdir/mem1.txt", MemoryLoadFileType.Binary) + +Which generates the bind module: + +```verilog +module BindsTo_0_Foo( + input clock, + input reset, + input [31:0] io_nia, + output [31:0] io_insn +); + +initial begin + $readmemh("test.hex", Foo.memory); +end +endmodule + +bind Foo BindsTo_0_Foo BindsTo_0_Foo_Inst(.*); ``` -See: [ComplexMemoryLoadingSpec.scala](https://freechipsproject/chisel-testers/src/test/scala/examples/ComplexMemoryLoadingSpec.scala) and -[LoadMemoryFromFileSpec.scala](https://github.com/freechipsproject/chisel-testers/src/test/scala/examples/LoadMemoryFromFileSpec.scala) -for working examples. ### Notes on files -There is no simple answer to where to put this file. It's probably best to create a resource directory somewhere and reference that through a full path. Because these files may be large, we did not want to copy them. + +There is no simple answer to where to put the `hex` or `bin` file with the initial contents. It's probably best to create a resource directory somewhere and reference that through a full path or place the file beside the generated Verilog. Another option is adding the path to the memory file in the synthesis tool path. Because these files may be large, Chisel does not copy them. > Don't forget there is no decimal option, so a 10 in an input file will be 16 decimal +See: [ComplexMemoryLoadingSpec.scala](https://github.com/freechipsproject/chisel-testers/blob/master/src/test/scala/examples/ComplexMemoryLoadingSpec.scala) and +[LoadMemoryFromFileSpec.scala](https://github.com/freechipsproject/chisel-testers/blob/master/src/test/scala/examples/LoadMemoryFromFileSpec.scala) +for working examples. + + ### Aggregate memories + Aggregate memories are supported but in bit of a clunky way. Since they will be split up into a memory per field, the following convention was adopted. When specifying the file for such a memory the file name should be regarded as a template. If the memory is a Bundle e.g. + ```scala mdoc:compile-only class MemDataType extends Bundle { val a = UInt(16.W) @@ -193,6 +286,7 @@ class MemDataType extends Bundle { val c = Bool() } ``` + The memory will be split into `memory_a`, `memory_b`, and `memory_c`. Similarly if a load file is specified as `"memory-load.txt"` the simulation will expect that there will be three files, `"memory-load_a.txt"`, `"memory-load_b.txt"`, `"memory-load_c.txt"` > Note: The use of `_` and that the memory field name is added before any file suffix. The suffix is optional but if present is considered to be the text after the last `.` in the file name. diff --git a/docs/src/explanations/memories.md b/docs/src/explanations/memories.md index 792d176e..09ac4c8d 100644 --- a/docs/src/explanations/memories.md +++ b/docs/src/explanations/memories.md @@ -11,9 +11,11 @@ Chisel provides facilities for creating both read only and read/write memories. ## ROM Users can define read only memories with a `Vec`: + ```scala mdoc:invisible import chisel3._ ``` + ``` scala mdoc:compile-only VecInit(inits: Seq[T]) VecInit(elt0: T, elts: T*) @@ -56,6 +58,7 @@ If the same memory address is both written and sequentially read on the same clo Values on the read data port are not guaranteed to be held until the next read cycle. If that is the desired behavior, external logic to hold the last read value must be added. #### Read port/write port + Ports into `SyncReadMem`s are created by applying a `UInt` index. A 1024-entry SRAM with one write port and one read port might be expressed as follows: ```scala mdoc:silent @@ -79,9 +82,11 @@ class ReadWriteSmem extends Module { Below is an example waveform of the one write port/one read port `SyncReadMem` with [masks](#masks). Note that the signal names will differ from the exact wire names generated for the `SyncReadMem`. With masking, it is also possible that multiple RTL arrays will be generated with the behavior below. -![read/write ports example waveform](https://svg.wavedrom.com/github/freechipsproject/www.chisel-lang.org/master/docs/src/main/tut/chisel3/memories_waveforms/smem_read_write.json) +![read/write ports example waveform](https://svg.wavedrom.com/github/freechipsproject/www.chisel-lang.org/master/docs/src/main/resources/json/smem_read_write.json) + #### Single-ported + Single-ported SRAMs can be inferred when the read and write conditions are mutually exclusive in the same `when` chain: ```scala mdoc:silent @@ -110,7 +115,7 @@ class RWSmem extends Module { Here is an example single read/write port waveform, with [masks](#masks) (again, generated signal names and number of arrays may differ): -![read/write ports example waveform](https://svg.wavedrom.com/github/freechipsproject/www.chisel-lang.org/master/docs/src/main/tut/chisel3/memories_waveforms/smem_rw.json) +![read/write ports example waveform](https://svg.wavedrom.com/github/freechipsproject/www.chisel-lang.org/master/docs/src/main/resources/json/smem_rw.json) ### `Mem`: combinational/asynchronous-read, sequential/synchronous-write @@ -174,3 +179,9 @@ class MaskedRWSmem extends Module { } ``` +### Memory Initialization + +Chisel memories can be initialized from an external `binary` or `hex` file emitting proper Verilog for synthesis or simulation. There are multiple modes of initialization. + +For more information, check the experimental docs on [Loading Memories](../appendix/experimental-features#loading-memories) feature. + -- cgit v1.2.3 From 6e22d91ed31206292f9f8b02a89fe18885ad602d Mon Sep 17 00:00:00 2001 From: Megan Wachs Date: Mon, 12 Apr 2021 11:19:20 -0700 Subject: Add "how to tie off to 0" to the Cookbook (#1857) --- docs/src/cookbooks/cookbook.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'docs') diff --git a/docs/src/cookbooks/cookbook.md b/docs/src/cookbooks/cookbook.md index 6a8eeebf..b85ceadc 100644 --- a/docs/src/cookbooks/cookbook.md +++ b/docs/src/cookbooks/cookbook.md @@ -12,6 +12,7 @@ Please note that these examples make use of [Chisel's scala-style printing](../e * Converting Chisel Types to/from UInt * [How do I create a UInt from an instance of a Bundle?](#how-do-i-create-a-uint-from-an-instance-of-a-bundle) * [How do I create a Bundle from a UInt?](#how-do-i-create-a-bundle-from-a-uint) + * [How can I tieoff a Bundle/Vec to 0?](#how-can-i-tieoff-a-bundlevec-to-0) * [How do I create a Vec of Bools from a UInt?](#how-do-i-create-a-vec-of-bools-from-a-uint) * [How do I create a UInt from a Vec of Bool?](#how-do-i-create-a-uint-from-a-vec-of-bool) * Vectors and Registers @@ -66,6 +67,36 @@ class Foo extends RawModule { } ``` +### How can I tieoff a Bundle/Vec to 0? + +You can use `asTypeOf` as above. If you don't want to worry about the type of the thing +you are tying off, you can use `chiselTypeOf`: + +```scala mdoc:silent:reset +import chisel3._ + +class MyBundle extends Bundle { + val foo = UInt(4.W) + val bar = Vec(4, UInt(1.W)) +} + +class Foo(typ: Data) extends RawModule { + val bundleA = IO(Output(typ)) + val bundleB = IO(Output(typ)) + + // typ is already a Chisel Data Type, so can use it directly here, but you + // need to know that bundleA is of type typ + bundleA := 0.U.asTypeOf(typ) + + // bundleB is a Hardware data IO(Output(...)) so need to call chiselTypeOf, + // but this will work no matter the type of bundleB: + bundleB := 0.U.asTypeOf(chiselTypeOf(bundleB)) +} + +class Bar extends RawModule { + val foo = Module(new Foo(new MyBundle())) +} +``` ### How do I create a Vec of Bools from a UInt? Use [`VecInit`](https://www.chisel-lang.org/api/latest/chisel3/VecInit$.html) given a `Seq[Bool]` generated using the [`asBools`](https://www.chisel-lang.org/api/latest/chisel3/UInt.html#asBools():Seq[chisel3.Bool]) method. -- cgit v1.2.3 From f39ec2ef5a3b2140b43d631056c2f974ca1895d5 Mon Sep 17 00:00:00 2001 From: Carlos Eduardo Date: Wed, 14 Apr 2021 22:38:41 -0300 Subject: Fix doc formatting and generation (#1863) * Remove space between backticks and language * Make code examples in memories explanation work Co-authored-by: Jack Koenig --- docs/src/explanations/memories.md | 40 +++++++++++----------- .../polymorphism-and-parameterization.md | 9 +++-- docs/src/explanations/sequential-circuits.md | 2 +- 3 files changed, 27 insertions(+), 24 deletions(-) (limited to 'docs') diff --git a/docs/src/explanations/memories.md b/docs/src/explanations/memories.md index 09ac4c8d..1f2f83be 100644 --- a/docs/src/explanations/memories.md +++ b/docs/src/explanations/memories.md @@ -10,36 +10,36 @@ Chisel provides facilities for creating both read only and read/write memories. ## ROM -Users can define read only memories with a `Vec`: +Users can define read-only memories by constructing a `Vec` with `VecInit`. +`VecInit` can except either a variable-argument number of `Data` literals or a `Seq[Data]` literals that initialize the ROM. ```scala mdoc:invisible import chisel3._ +// This is bad, don't do this, use a val +def counter = util.Counter(true.B, 4)._1 +val Pi = 3.14 +def sin(t: Double): Double = t // What should this be? ``` -``` scala mdoc:compile-only - VecInit(inits: Seq[T]) - VecInit(elt0: T, elts: T*) -``` - -where `inits` is a sequence of initial `Data` literals that initialize the ROM. For example, users cancreate a small ROM initialized to 1, 2, 4, 8 and loop through all values using a counter as an address generator as follows: +For example, users can create a small ROM initialized to 1, 2, 4, 8 and loop through all values using a counter as an address generator as follows: -``` scala mdoc:compile-only - val m = VecInit(Array(1.U, 2.U, 4.U, 8.U)) - val r = m(counter(m.length.U)) +```scala mdoc:compile-only +val m = VecInit(1.U, 2.U, 4.U, 8.U) +val r = m(counter(m.length.U)) ``` We can create an *n* value sine lookup table using a ROM initialized as follows: -``` scala mdoc:silent - def sinTable(amp: Double, n: Int) = { - val times = - (0 until n).map(i => (i*2*Pi)/(n.toDouble-1) - Pi) - val inits = - times.map(t => round(amp * sin(t)).asSInt(32.W)) - VecInit(inits) - } - def sinWave(amp: Double, n: Int) = - sinTable(amp, n)(counter(n.U)) +```scala mdoc:compile-only +def sinTable(amp: Double, n: Int) = { + val times = + (0 until n).map(i => (i*2*Pi)/(n.toDouble-1) - Pi) + val inits = + times.map(t => Math.round(amp * sin(t)).asSInt(32.W)) + VecInit(inits) +} +def sinWave(amp: Double, n: Int) = + sinTable(amp, n)(counter(n.U)) ``` where `amp` is used to scale the fixpoint values stored in the ROM. diff --git a/docs/src/explanations/polymorphism-and-parameterization.md b/docs/src/explanations/polymorphism-and-parameterization.md index 94b896b1..9b69ed05 100644 --- a/docs/src/explanations/polymorphism-and-parameterization.md +++ b/docs/src/explanations/polymorphism-and-parameterization.md @@ -231,7 +231,10 @@ class X[T <: BaseModule with MyAdder](genT: => T) extends Module { println(ChiselStage.emitVerilog(new X(new Mod1))) println(ChiselStage.emitVerilog(new X(new Mod2))) ``` -```scala mdoc:passthrough -println(ChiselStage.emitVerilog(new X(new Mod1))) -println(ChiselStage.emitVerilog(new X(new Mod2))) + +Output: + +```scala mdoc:verilog +ChiselStage.emitVerilog(new X(new Mod1)) +ChiselStage.emitVerilog(new X(new Mod2)) ``` diff --git a/docs/src/explanations/sequential-circuits.md b/docs/src/explanations/sequential-circuits.md index 938416ac..36bbb1aa 100644 --- a/docs/src/explanations/sequential-circuits.md +++ b/docs/src/explanations/sequential-circuits.md @@ -11,7 +11,7 @@ import chisel3._ val in = Bool() ``` The simplest form of state element supported by Chisel is a positive edge-triggered register, which can be instantiated as: -``` scala mdoc:compile-only +```scala mdoc:compile-only val reg = RegNext(in) ``` This circuit has an output that is a copy of the input signal `in` delayed by one clock cycle. Note that we do not have to specify the type of Reg as it will be automatically inferred from its input when instantiated in this way. In the current version of Chisel, clock and reset are global signals that are implicitly included where needed. -- cgit v1.2.3 From 83eeda2efebb1e3e3d66365d388f5de627766d47 Mon Sep 17 00:00:00 2001 From: Fabien Marteau Date: Mon, 19 Apr 2021 20:01:27 +0200 Subject: Update polymorphism-and-parameterization.md (#1868) nitpick--- docs/src/explanations/polymorphism-and-parameterization.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/src/explanations/polymorphism-and-parameterization.md b/docs/src/explanations/polymorphism-and-parameterization.md index 9b69ed05..b388ee5b 100644 --- a/docs/src/explanations/polymorphism-and-parameterization.md +++ b/docs/src/explanations/polymorphism-and-parameterization.md @@ -4,7 +4,7 @@ title: "Polymorphism and Parameterization" section: "chisel3" --- -# Polymorphism and Paramterization +# Polymorphism and Parameterization _This section is advanced and can be skipped at first reading._ -- cgit v1.2.3 From 23b3fe8a6a2db92599bb0775626425056d47d1de Mon Sep 17 00:00:00 2001 From: Megan Wachs Date: Mon, 26 Apr 2021 16:02:54 -0700 Subject: Cookbooks: make examples more clear and remove naming (#1881) Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>--- docs/src/cookbooks/cookbook.md | 92 ++++++++++++------------------------------ 1 file changed, 26 insertions(+), 66 deletions(-) (limited to 'docs') diff --git a/docs/src/cookbooks/cookbook.md b/docs/src/cookbooks/cookbook.md index b85ceadc..290a6c82 100644 --- a/docs/src/cookbooks/cookbook.md +++ b/docs/src/cookbooks/cookbook.md @@ -46,6 +46,10 @@ class Foo extends RawModule { bundle.foo := 0xc.U bundle.bar := 0x3.U val uint = bundle.asUInt + printf(p"$uint") // 195 + + // Test + assert(uint === 0xc3.U) } ``` @@ -64,6 +68,12 @@ class MyBundle extends Bundle { class Foo extends RawModule { val uint = 0xb4.U val bundle = uint.asTypeOf(new MyBundle) + + printf(p"$bundle") // Bundle(foo -> 11, bar -> 4) + + // Test + assert(bundle.foo === 0xb.U) + assert(bundle.bar === 0x4.U) } ``` @@ -107,6 +117,14 @@ import chisel3._ class Foo extends RawModule { val uint = 0xc.U val vec = VecInit(uint.asBools) + + printf(p"$vec") // Vec(0, 0, 1, 1) + + // Test + assert(vec(0) === false.B) + assert(vec(1) === false.B) + assert(vec(2) === true.B) + assert(vec(3) === true.B) } ``` @@ -120,6 +138,13 @@ import chisel3._ class Foo extends RawModule { val vec = VecInit(true.B, false.B, true.B, true.B) val uint = vec.asUInt + + printf(p"$uint") // 13 + + // Test + // (remember leftmost Bool in Vec is low order bit) + assert(0xd.U === uint) + } ``` @@ -331,73 +356,8 @@ class ModuleWithOptionalIO(flag: Boolean) extends Module { ### How do I get Chisel to name signals properly in blocks like when/withClockAndReset? -To get Chisel to name signals (wires and registers) declared inside of blocks like `when`, `withClockAndReset`, etc, use the [`@chiselName`](https://www.chisel-lang.org/api/latest/chisel3/experimental/package$$chiselName.html) annotation as shown below: - -```scala mdoc:silent:reset -import chisel3._ -import chisel3.experimental.chiselName - -@chiselName -class TestMod extends Module { - val io = IO(new Bundle { - val a = Input(Bool()) - val b = Output(UInt(4.W)) - }) - when (io.a) { - val innerReg = RegInit(5.U(4.W)) - innerReg := innerReg + 1.U - io.b := innerReg - } .otherwise { - io.b := 10.U - } -} -``` - -Note that you will need to add the following line to your project's `build.sbt` file. - -```scala -addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full) -``` - -If we compile this module *without* `@chiselName`, Chisel is not able to name `innerReg` correctly (notice the `_T`): - -```scala mdoc:passthrough -import chisel3.stage.{ChiselStage, ChiselGeneratorAnnotation} -import firrtl.annotations.DeletedAnnotation -import firrtl.EmittedVerilogCircuitAnnotation - -class TestModWithout extends Module { - override val desiredName = "TestMod" - val io = IO(new Bundle { - val a = Input(Bool()) - val b = Output(UInt(4.W)) - }) - when (io.a) { - val innerReg = RegInit(5.U(4.W)) - innerReg := innerReg + 1.U - io.b := innerReg - } .otherwise { - io.b := 10.U - } -} +Use the compiler plugin, and check out the [Naming Cookbook](#naming) if that still does not do what you want. -(new ChiselStage) - .execute(Array("-X", "verilog"), Seq(ChiselGeneratorAnnotation(() => new TestModWithout))) - .collectFirst{ case DeletedAnnotation(_, a: EmittedVerilogCircuitAnnotation) => a.value.value } - .foreach(a => println(s"""|```verilog - |$a - |```""".stripMargin)) -``` - -However, if we use `@chiselName` then the register previously called `_T` is now `innerReg`: -```scala mdoc:passthrough -(new ChiselStage) - .execute(Array("-X", "verilog"), Seq(ChiselGeneratorAnnotation(() => new TestMod))) - .collectFirst{ case DeletedAnnotation(_, a: EmittedVerilogCircuitAnnotation) => a.value.value } - .foreach(a => println(s"""|```verilog - |$a - |```""".stripMargin)) -``` ### How do I get Chisel to name the results of vector reads properly? Currently, name information is lost when using dynamic indexing. For example: ```scala mdoc:silent -- cgit v1.2.3 From 6deb379b1d8bafc81a605f60476bf0f24eac60b4 Mon Sep 17 00:00:00 2001 From: Chick Markley Date: Tue, 27 Apr 2021 12:17:17 -0700 Subject: Introduce VecLiterals (#1834) This PR provides for support for Vec literals. They can be one of two forms Inferred: ``` Vec.Lit(0x1.U, 0x2.U) ``` or explicit: ``` Vec(2, UInt(4.W)).Lit(0 -> 0x1.U, 1 -> 0x2.U) ``` - Explicit form allows for partial, or sparse, literals. - Vec literals can be used as Register initializers - Arbitrary nesting (consistent with type constraints is allowed)--- docs/src/appendix/experimental-features.md | 82 +++++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) (limited to 'docs') diff --git a/docs/src/appendix/experimental-features.md b/docs/src/appendix/experimental-features.md index 363f7a06..4b1208aa 100644 --- a/docs/src/appendix/experimental-features.md +++ b/docs/src/appendix/experimental-features.md @@ -85,7 +85,87 @@ class Example3 extends RawModule { chisel3.stage.ChiselStage.emitVerilog(new Example3) ``` -Vec literals are not yet supported. +### Vec Literals + +Vec literals are very similar to Bundle literals and can be constructed via an experimental import. +They can be constructed in two forms, with type and length inferred as in: + +```scala mdoc +import chisel3._ +import chisel3.experimental.VecLiterals._ + +class VecExample1 extends Module { + val out = IO(Output(Vec(2, UInt(4.W)))) + out := Vec.Lit(0xa.U, 0xbb.U) +} +``` +```scala mdoc:verilog +chisel3.stage.ChiselStage.emitVerilog(new VecExample1) +``` + +or explicitly as in: + +```scala mdoc +import chisel3._ +import chisel3.experimental.VecLiterals._ + +class VecExample1a extends Module { + val out = IO(Output(Vec(2, UInt(4.W)))) + out := Vec(2, UInt(4.W)).Lit(0 -> 1.U, 1 -> 2.U) +} +``` + +```scala mdoc:verilog +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 + +```scala mdoc +class VecExample2 extends RawModule { + val out = IO(Output(Vec(4, UInt(4.W)))) + out := Vec(4, UInt(4.W)).Lit(0 -> 1.U, 3 -> 7.U) +} +``` + +```scala mdoc:verilog +chisel3.stage.ChiselStage.emitVerilog(new VecExample2) +``` + +Registers can be initialized from Vec literals + +```scala mdoc +class VecExample3 extends Module { + val out = IO(Output(Vec(4, UInt(8.W)))) + val y = RegInit( + Vec(4, UInt(8.W)).Lit(0 -> 0xAB.U(8.W), 1 -> 0xCD.U(8.W), 2 -> 0xEF.U(8.W), 3 -> 0xFF.U(8.W)) + ) + out := y +} +``` + +```scala mdoc:verilog +chisel3.stage.ChiselStage.emitVerilog(new VecExample3) +``` + +Vec literals can also be nested arbitrarily. + +```scala mdoc +class VecExample5 extends RawModule { + val out = IO(Output(Vec(2, new ChildBundle))) + out := Vec(2, new ChildBundle).Lit( + 0 -> (new ChildBundle).Lit(_.foo -> 42.U), + 1 -> (new ChildBundle).Lit(_.foo -> 7.U) + ) +} +``` + +```scala mdoc:verilog +chisel3.stage.ChiselStage.emitVerilog(new VecExample5) +``` ### Interval Type -- cgit v1.2.3 From 9fdea534f83578f745ec22cc7e530105f9fd67f7 Mon Sep 17 00:00:00 2001 From: Megan Wachs Date: Wed, 28 Apr 2021 10:57:13 -0700 Subject: Cookbook: clean up desiredName example (#1886) * Cookbook: clean up desiredName example * Update cookbook.md--- docs/src/cookbooks/cookbook.md | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) (limited to 'docs') diff --git a/docs/src/cookbooks/cookbook.md b/docs/src/cookbooks/cookbook.md index 290a6c82..1b47ad14 100644 --- a/docs/src/cookbooks/cookbook.md +++ b/docs/src/cookbooks/cookbook.md @@ -447,16 +447,13 @@ class Salt extends Module { } ``` -Elaborating the Chisel module `Salt` yields our "desire name" for `Salt` and `Coffee` in the output Verilog: -```scala mdoc:passthrough -import chisel3.stage.{ChiselStage, ChiselGeneratorAnnotation} -import firrtl.annotations.DeletedAnnotation -import firrtl.EmittedVerilogCircuitAnnotation - -(new ChiselStage) - .execute(Array("-X", "verilog"), Seq(ChiselGeneratorAnnotation(() => new Salt))) - .collectFirst{ case DeletedAnnotation(_, a: EmittedVerilogCircuitAnnotation) => a.value.value } - .foreach(a => println(s"""|```verilog - |$a - |```""".stripMargin)) +Elaborating the Chisel module `Salt` yields our "desired names" for `Salt` and `Coffee` in the output Verilog: +```scala mdoc:silent +import chisel3.stage.ChiselStage + +ChiselStage.emitVerilog(new Salt) +``` + +```scala mdoc:verilog +ChiselStage.emitVerilog(new Salt) ``` -- cgit v1.2.3 From 1875d3dae18a518d303472cb0b022c1180797b90 Mon Sep 17 00:00:00 2001 From: Martin Schoeberl Date: Thu, 20 May 2021 22:49:36 +0200 Subject: doc: link to developer style guide (#1929) --- docs/src/developers/developers.md | 1 + 1 file changed, 1 insertion(+) (limited to 'docs') diff --git a/docs/src/developers/developers.md b/docs/src/developers/developers.md index b2b5dff8..7072af6b 100644 --- a/docs/src/developers/developers.md +++ b/docs/src/developers/developers.md @@ -10,3 +10,4 @@ Tips and tricks for Chisel developers: * [Embedding Chisel as an sbt subproject](sbt-subproject) * [Test Coverage](test-coverage) +* [Developers Style Guide](style) -- cgit v1.2.3 From 5e8ef455d8f911c05ae858ef05bb2d16a91d9b0a Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Fri, 25 Jun 2021 13:41:19 -0700 Subject: Update type_hierarchy (#1977) * Add Clock * Add Analog * Add Interval * Add line from User Types (...) to Record--- docs/src/images/type_hierarchy.dot | 18 ++- docs/src/images/type_hierarchy.png | Bin 34477 -> 45913 bytes docs/src/images/type_hierarchy.svg | 272 ++++++++++++++++++++++--------------- 3 files changed, 172 insertions(+), 118 deletions(-) (limited to 'docs') diff --git a/docs/src/images/type_hierarchy.dot b/docs/src/images/type_hierarchy.dot index d3bf6eb4..b98cc269 100644 --- a/docs/src/images/type_hierarchy.dot +++ b/docs/src/images/type_hierarchy.dot @@ -10,7 +10,10 @@ digraph TypeHierarchy { "Chisel Internal" } { node [fillcolor="#e5f5e0"] - Bool UInt SInt FixedPoint + Bool UInt SInt + FixedPoint Interval + Analog + Clock Reset AsyncReset Record @@ -27,8 +30,9 @@ digraph TypeHierarchy { color=transparent Element Bits Num - Reset - Bool UInt SInt FixedPoint + Reset Clock Analog + UInt SInt FixedPoint Interval + Bool color=transparent Aggregate VecLike @@ -37,10 +41,12 @@ digraph TypeHierarchy { Vec {Aggregate Element} -> Data - {Bits Reset} -> Element - {FixedPoint SInt UInt} -> {Bits Num} + {Bits Reset Clock Analog} -> Element + {UInt SInt FixedPoint Interval} -> {Bits Num} Bool -> {UInt Reset} - Ellipsis -> Bundle -> Record -> Aggregate + Ellipsis -> Bundle + Ellipsis -> Record -> Aggregate + Bundle -> Record Vec -> {Aggregate VecLike} AsyncReset -> {Element Reset} } diff --git a/docs/src/images/type_hierarchy.png b/docs/src/images/type_hierarchy.png index f3947975..9c4f74f1 100644 Binary files a/docs/src/images/type_hierarchy.png and b/docs/src/images/type_hierarchy.png differ diff --git a/docs/src/images/type_hierarchy.svg b/docs/src/images/type_hierarchy.svg index c120daba..faf23a1e 100644 --- a/docs/src/images/type_hierarchy.svg +++ b/docs/src/images/type_hierarchy.svg @@ -1,261 +1,309 @@ - - + TypeHierarchy cluster_data_hierarchy - + cluster_legend - -Legend + +Legend Data - -Data + +Data Element - -Element + +Element Element->Data - - + + Bits - -Bits + +Bits Bits->Element - - + + Num - -Num + +Num Aggregate - -Aggregate + +Aggregate Aggregate->Data - - + + VecLike - -VecLike + +VecLike Chisel Internal - -Chisel Internal + +Chisel Internal Bool - -Bool + +Bool UInt - -UInt + +UInt - + Bool->UInt - - + + - + Reset - -Reset + +Reset - + Bool->Reset - - + + - + UInt->Bits - - + + - + UInt->Num - - + + SInt - -SInt + +SInt - + SInt->Bits - - + + - + SInt->Num - - + + FixedPoint - -FixedPoint + +FixedPoint - + FixedPoint->Bits - - + + - + FixedPoint->Num - - + + - + + +Interval + +Interval + + + +Interval->Bits + + + + + +Interval->Num + + + + + +Analog + +Analog + + +Analog->Element + + + + + +Clock + +Clock + + + +Clock->Element + + + + + Reset->Element - - + + - + AsyncReset - -AsyncReset + +AsyncReset - + AsyncReset->Element - - + + - + AsyncReset->Reset - - + + - + Record - -Record + +Record - + Record->Aggregate - - + + - + Bundle - -Bundle + +Bundle - + Bundle->Record - - + + - + Vec - -Vec + +Vec - + Vec->Aggregate - - + + - + Vec->VecLike - - + + - + Chisel Types - -Chisel Types + +Chisel Types - + Chisel Types->Chisel Internal - - + + - + User Types - -User Types + +User Types - + User Types->Chisel Types - - + + - + Ellipsis - -... + +... + + + +Ellipsis->Record + + - + Ellipsis->Bundle - - + + -- cgit v1.2.3 From bfb77d4cc1163e34cc54ce856214a0181b2cb029 Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Thu, 1 Jul 2021 18:03:55 -0700 Subject: Update docs for ChiselEnum --- docs/src/explanations/chisel-enum.md | 170 ++++++++++++++++++++++++----------- 1 file changed, 118 insertions(+), 52 deletions(-) (limited to 'docs') diff --git a/docs/src/explanations/chisel-enum.md b/docs/src/explanations/chisel-enum.md index cb017239..3f0f3b18 100644 --- a/docs/src/explanations/chisel-enum.md +++ b/docs/src/explanations/chisel-enum.md @@ -1,4 +1,4 @@ ---- +--- layout: docs title: "Enumerations" section: "chisel3" @@ -6,8 +6,8 @@ section: "chisel3" # ChiselEnum -The ChiselEnum type can be used to reduce the chance of error when encoding mux selectors, opcodes, and functional unit operations. In contrast with`Chisel.util.Enum`, `ChiselEnum` are subclasses of `Data`, which means that they can be used to define fields in `Bundle`s, including in `IO`s. - +The ChiselEnum type can be used to reduce the chance of error when encoding mux selectors, opcodes, and functional unit operations. +In contrast with `Chisel.util.Enum`, `ChiselEnum` are subclasses of `Data`, which means that they can be used to define fields in `Bundle`s, including in `IO`s. ## Functionality and Examples @@ -19,57 +19,68 @@ import chisel3.stage.ChiselStage import chisel3.experimental.ChiselEnum ``` -Below we see ChiselEnum being used as mux select for a RISC-V core. While wrapping the object in a package is not required, it is highly recommended as it allows for the type to be used in multiple files more easily. +```scala mdoc:invisible +// Helper to print stdout from Chisel elab +// May be related to: https://github.com/scalameta/mdoc/issues/517 +import java.io._ +import _root_.logger.Logger +def grabLog[T](thunk: => T): (String, T) = { + val baos = new ByteArrayOutputStream() + val stream = new PrintStream(baos, true, "utf-8") + val ret = Logger.makeScope(Nil) { + Logger.setOutput(stream) + thunk + } + (baos.toString, ret) +} +``` + +Below we see ChiselEnum being used as mux select for a RISC-V core. While wrapping the object in a package is not required, it is highly recommended as it allows for the type to be used in multiple files more easily. ```scala mdoc // package CPUTypes { - object AluMux1Sel extends ChiselEnum { - val selectRS1, selectPC = Value - /** How the values will be mapped - "selectRS1" -> 0.U, - "selectPC" -> 1.U - */ - } -// } +object AluMux1Sel extends ChiselEnum { + val selectRS1, selectPC = Value +} +// We can see the mapping by printing each Value +AluMux1Sel.all.foreach(println) ``` -Here we see a mux using the AluMux1Sel to select between different inputs. +Here we see a mux using the AluMux1Sel to select between different inputs. ```scala mdoc import AluMux1Sel._ class AluMux1Bundle extends Bundle { - val aluMux1Sel = Input( AluMux1Sel() ) - val rs1Out = Input(Bits(32.W)) - val pcOut = Input(Bits(32.W)) - val aluMux1Out = Output(Bits(32.W)) + val aluMux1Sel = Input(AluMux1Sel()) + val rs1Out = Input(Bits(32.W)) + val pcOut = Input(Bits(32.W)) + val aluMux1Out = Output(Bits(32.W)) } class AluMux1File extends Module { - val io = IO(new AluMux1Bundle) - - // Default value for aluMux1Out - io.aluMux1Out := 0.U - - switch (io.aluMux1Sel) { - is (selectRS1) { - io.aluMux1Out := io.rs1Out - } - is (selectPC) { - io.aluMux1Out := io.pcOut - } + val io = IO(new AluMux1Bundle) + + // Default value for aluMux1Out + io.aluMux1Out := 0.U + + switch (io.aluMux1Sel) { + is (selectRS1) { + io.aluMux1Out := io.rs1Out } + is (selectPC) { + io.aluMux1Out := io.pcOut + } + } } ``` ```scala mdoc:verilog -ChiselStage.emitVerilog(new AluMux1File ) +ChiselStage.emitVerilog(new AluMux1File) ``` -ChiselEnum also allows for the user to define variables by passing in the value shown below. Note that the value must be increasing or else - - > chisel3.internal.ChiselException: Exception thrown when elaborating ChiselGeneratorAnnotation - -is thrown during Verilog generation. +ChiselEnum also allows for the user to directly set the Values by passing an `UInt` to `Value(...)` +as shown below. Note that the magnitude of each `Value` must be strictly greater than the one before +it. ```scala mdoc object Opcode extends ChiselEnum { @@ -85,27 +96,81 @@ object Opcode extends ChiselEnum { } ``` -The user can 'jump' to a value and continue incrementing by passing a start point then using a regular Value assignment. +The user can 'jump' to a value and continue incrementing by passing a start point then using a regular Value definition. ```scala mdoc object BranchFunct3 extends ChiselEnum { val beq, bne = Value val blt = Value(4.U) val bge, bltu, bgeu = Value - /** How the values will be mapped - "beq" -> 0.U, - "bne" -> 1.U, - "blt" -> 4.U, - "bge" -> 5.U, - "bltu" -> 6.U, - "bgeu" -> 7.U - */ } +// We can see the mapping by printing each Value +BranchFunct3.all.foreach(println) +``` + +## Casting + +You can cast an enum to a `UInt` using `.asUInt`: + +```scala mdoc +class ToUInt extends RawModule { + val in = IO(Input(Opcode())) + val out = IO(Output(UInt())) + out := in.asUInt +} +``` + +```scala mdoc:invisible +// Always need to run Chisel to see if there are elaboration errors +ChiselStage.emitVerilog(new ToUInt) +``` + +You can cast from a `UInt` to an enum by passing the `UInt` to the apply method of the `ChiselEnum` object: + +```scala mdoc +class FromUInt extends Module { + val in = IO(Input(UInt(7.W))) + val out = IO(Output(Opcode())) + out := Opcode(in) +} +``` + +However, if you cast from a `UInt` to an Enum type when there are undefined states in the Enum values +that the `UInt` could hit, you will see a warning like the following: + +```scala mdoc:passthrough +val (log, _) = grabLog(ChiselStage.emitChirrtl(new FromUInt)) +println(s"```$log```") +``` +(Note that the name of the Enum is ugly as an artifact of our documentation generation flow, it will +be cleaner in normal use). + +You can avoid this warning by using the `.safe` factory method which returns the cast Enum in addition +to a `Bool` indicating if the Enum is in a valid state: + +```scala mdoc +class SafeFromUInt extends Module { + val in = IO(Input(UInt(7.W))) + val out = IO(Output(Opcode())) + val (value, valid) = Opcode.safe(in) + assert(valid, "Enum state must be valid, got %d!", in) + out := value +} +``` + +Now there will be no warning: + +```scala mdoc:passthrough +val (log2, _) = grabLog(ChiselStage.emitChirrtl(new SafeFromUInt)) +println(s"```$log2```") ``` ## Testing -When testing your modules, the `.Type` and `.litValue` attributes allow for the the objects to be passed as parameters and for the value to be converted to BigInt type. Note that BigInts cannot be casted to Int with `.asInstanceOf[Int]`, they use their own methods like `toInt`. Please review the [scala.math.BigInt](https://www.scala-lang.org/api/2.12.5/scala/math/BigInt.html) page for more details! +The _Type_ of the enums values is `.Type` which can be useful for passing the values +as parameters to a function (or any other time a type annotation is needed). +Calling `.litValue` on an enum value will return the integer value of that object as a +[`BigInt`](https://www.scala-lang.org/api/2.12.13/scala/math/BigInt.html). ```scala mdoc def expectedSel(sel: AluMux1Sel.Type): Boolean = sel match { @@ -115,22 +180,23 @@ def expectedSel(sel: AluMux1Sel.Type): Boolean = sel match { } ``` -The ChiselEnum type also has methods `.all` and `.getWidth` where `all` returns all of the enum instances and `getWidth` returns the width of the hardware type. +Some additional useful methods defined on the `ChiselEnum` object are: +* `.all`: returns the enum values within the enumeration +* `.getWidth`: returns the width of the hardware type ## Workarounds -As of 2/26/2021, the width of the values is always inferred. To work around this, you can add an extra `Value` that forces the width that is desired. This is shown in the example below, where we add a field `ukn` to force the width to be 3 bits wide: +As of Chisel v3.4.3 (1 July 2020), the width of the values is always inferred. +To work around this, you can add an extra `Value` that forces the width that is desired. +This is shown in the example below, where we add a field `ukn` to force the width to be 3 bits wide: ```scala mdoc object StoreFunct3 extends ChiselEnum { val sb, sh, sw = Value val ukn = Value(7.U) - /** How the values will be mapped - "sb" -> 0.U, - "sh" -> 1.U, - "sw" -> 2.U - */ } +// We can see the mapping by printing each Value +StoreFunct3.all.foreach(println) ``` Signed values are not supported so if you want the value signed, you must cast the UInt with `.asSInt`. -- cgit v1.2.3 From 558df41db062a14f52617fc44edd0aff569afa67 Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Wed, 7 Jul 2021 16:56:35 -0700 Subject: Fix ChiselEnum docs (#2016) Also add newline to end of `verilog` modifier code blocks so that there is always a newline between code blocks and following material.--- docs/src/explanations/chisel-enum.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'docs') diff --git a/docs/src/explanations/chisel-enum.md b/docs/src/explanations/chisel-enum.md index 3f0f3b18..96fc9e8a 100644 --- a/docs/src/explanations/chisel-enum.md +++ b/docs/src/explanations/chisel-enum.md @@ -74,6 +74,7 @@ class AluMux1File extends Module { } } ``` + ```scala mdoc:verilog ChiselStage.emitVerilog(new AluMux1File) ``` @@ -140,8 +141,9 @@ that the `UInt` could hit, you will see a warning like the following: ```scala mdoc:passthrough val (log, _) = grabLog(ChiselStage.emitChirrtl(new FromUInt)) -println(s"```$log```") +println(s"```\n$log```") ``` + (Note that the name of the Enum is ugly as an artifact of our documentation generation flow, it will be cleaner in normal use). @@ -162,7 +164,7 @@ Now there will be no warning: ```scala mdoc:passthrough val (log2, _) = grabLog(ChiselStage.emitChirrtl(new SafeFromUInt)) -println(s"```$log2```") +println(s"```\n$log2```") ``` ## Testing @@ -181,6 +183,7 @@ def expectedSel(sel: AluMux1Sel.Type): Boolean = sel match { ``` Some additional useful methods defined on the `ChiselEnum` object are: + * `.all`: returns the enum values within the enumeration * `.getWidth`: returns the width of the hardware type -- cgit v1.2.3 From bb520b8573328fda5f7b3c3892e6995fbe1b4239 Mon Sep 17 00:00:00 2001 From: Verneri Hirvonen Date: Thu, 8 Jul 2021 18:59:12 +0300 Subject: Add `isOneOf` method to `ChiselEnum` (#1966) * Add @ekiwi's code as a starting point * Add test for ChiselEnum isOneOf method * Make isOneOfTester naming consistent with other testers * Add scaladoc comments for isOneOf * Add isOneOf tests that use the method that takes variable number of args * Add guide level documentation example for isOneOf--- docs/src/explanations/chisel-enum.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'docs') diff --git a/docs/src/explanations/chisel-enum.md b/docs/src/explanations/chisel-enum.md index 96fc9e8a..a390aea4 100644 --- a/docs/src/explanations/chisel-enum.md +++ b/docs/src/explanations/chisel-enum.md @@ -182,6 +182,25 @@ def expectedSel(sel: AluMux1Sel.Type): Boolean = sel match { } ``` +The enum value type also defines some convenience methods for working with `ChiselEnum` values. For example, continuing with the RISC-V opcode +example, one could easily create hardware signal that is only asserted on LOAD/STORE operations (when the enum value is equal to `Opcode.load` +or `Opcode.store`) using the `.isOneOf` method: + +```scala mdoc +class LoadStoreExample extends Module { + val io = IO(new Bundle { + val opcode = Input(Opcode()) + val load_or_store = Output(Bool()) + }) + io.load_or_store := io.opcode.isOneOf(Opcode.load, Opcode.store) +} +``` + +```scala mdoc:invisible +// Always need to run Chisel to see if there are elaboration errors +ChiselStage.emitVerilog(new LoadStoreExample) +``` + Some additional useful methods defined on the `ChiselEnum` object are: * `.all`: returns the enum values within the enumeration -- cgit v1.2.3 From 75c00606df6a2ba48d5354f32d5dbe327552ad45 Mon Sep 17 00:00:00 2001 From: Chick Markley Date: Thu, 5 Aug 2021 09:36:24 -0700 Subject: Small changes to memory doc (#2062) * Small changes to memory doc - Fixed typo "except" => "accept" - Use `Counter` explicitly in ROM section example. * Fix counter doc compile error * remove invisible doc block in memory example * more small fixes to make mem example pass doc compile * Get rid of sine wave iterator in memory doc * get rid of tabs on VecInit example * get rid of tabs on VecInit example--- docs/src/explanations/memories.md | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) (limited to 'docs') diff --git a/docs/src/explanations/memories.md b/docs/src/explanations/memories.md index 1f2f83be..10759f25 100644 --- a/docs/src/explanations/memories.md +++ b/docs/src/explanations/memories.md @@ -11,35 +11,32 @@ Chisel provides facilities for creating both read only and read/write memories. ## ROM Users can define read-only memories by constructing a `Vec` with `VecInit`. -`VecInit` can except either a variable-argument number of `Data` literals or a `Seq[Data]` literals that initialize the ROM. - -```scala mdoc:invisible -import chisel3._ -// This is bad, don't do this, use a val -def counter = util.Counter(true.B, 4)._1 -val Pi = 3.14 -def sin(t: Double): Double = t // What should this be? -``` +`VecInit` can accept either a variable-argument number of `Data` literals or a `Seq[Data]` literals that initialize the ROM. For example, users can create a small ROM initialized to 1, 2, 4, 8 and loop through all values using a counter as an address generator as follows: ```scala mdoc:compile-only +import chisel3._ +import chisel3.util.Counter val m = VecInit(1.U, 2.U, 4.U, 8.U) -val r = m(counter(m.length.U)) +val c = Counter(m.length) +c.inc() +val r = m(c.value) ``` -We can create an *n* value sine lookup table using a ROM initialized as follows: +We can create an *n* value sine lookup table generator using a ROM initialized as follows: ```scala mdoc:compile-only +import chisel3._ + +val Pi = math.Pi def sinTable(amp: Double, n: Int) = { val times = (0 until n).map(i => (i*2*Pi)/(n.toDouble-1) - Pi) val inits = - times.map(t => Math.round(amp * sin(t)).asSInt(32.W)) + times.map(t => Math.round(amp * math.sin(t)).asSInt(32.W)) VecInit(inits) } -def sinWave(amp: Double, n: Int) = - sinTable(amp, n)(counter(n.U)) ``` where `amp` is used to scale the fixpoint values stored in the ROM. -- cgit v1.2.3 From 1ceb974c55c6785c21ab3934fa750ade0702e276 Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Thu, 12 Aug 2021 17:04:11 -0700 Subject: Add DataView (#1955) DataView is a mechanism for "viewing" Scala objects as a subtype of `Data`. Often, this is useful for viewing one subtype of `Data`, as another. One can think about a DataView as a cross between a customizable cast and an untagged union. A DataView has a Target type `T`, and a View type `V`. DataView requires that an implementation of `DataProduct` is available for Target types. DataProduct is a type class that provides a way to iterate on `Data` children of objects of implementing types. If a DataView is provided for a type T to a type V, then the function .viewAs[V] (of type T => V) is available. The object (of type T) returned by .viewAs is called a "View" and can be used as both an rvalue and an lvalue. Unlike when using an .asTypeOf cast, connecting to a "View" will connect to the associated field or fields of the underlying Target. DataView also enables .viewAsSupertype which is available for viewing Bundles as a parent Bundle type. It is similar to .viewAs but requires a prototype object of the Target type which will be cloned in order to create the returned View. .viewAsSupertype maps between the corresponding fields of the parent and child Bundle types.--- docs/src/cookbooks/cookbook.md | 9 +- docs/src/cookbooks/dataview.md | 179 +++++++++++++ docs/src/explanations/dataview.md | 520 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 706 insertions(+), 2 deletions(-) create mode 100644 docs/src/cookbooks/dataview.md create mode 100644 docs/src/explanations/dataview.md (limited to 'docs') diff --git a/docs/src/cookbooks/cookbook.md b/docs/src/cookbooks/cookbook.md index 1b47ad14..f033c285 100644 --- a/docs/src/cookbooks/cookbook.md +++ b/docs/src/cookbooks/cookbook.md @@ -9,12 +9,13 @@ section: "chisel3" Please note that these examples make use of [Chisel's scala-style printing](../explanations/printing#scala-style). -* Converting Chisel Types to/from UInt +* Type Conversions * [How do I create a UInt from an instance of a Bundle?](#how-do-i-create-a-uint-from-an-instance-of-a-bundle) * [How do I create a Bundle from a UInt?](#how-do-i-create-a-bundle-from-a-uint) * [How can I tieoff a Bundle/Vec to 0?](#how-can-i-tieoff-a-bundlevec-to-0) * [How do I create a Vec of Bools from a UInt?](#how-do-i-create-a-vec-of-bools-from-a-uint) * [How do I create a UInt from a Vec of Bool?](#how-do-i-create-a-uint-from-a-vec-of-bool) + * [How do I connect a subset of Bundle fields?](#how-do-i-connect-a-subset-of-bundle-fields) * Vectors and Registers * [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) @@ -27,7 +28,7 @@ Please note that these examples make use of [Chisel's scala-style printing](../e * [How do I get Chisel to name the results of vector reads properly?](#how-do-i-get-chisel-to-name-the-results-of-vector-reads-properly) * [How can I dynamically set/parametrize the name of a module?](#how-can-i-dynamically-setparametrize-the-name-of-a-module) -## Converting Chisel Types to/from UInt +## Type Conversions ### How do I create a UInt from an instance of a Bundle? @@ -148,6 +149,10 @@ class Foo extends RawModule { } ``` +### How do I connect a subset of Bundle fields? + +See the [DataView cookbook](dataview#how-do-i-connect-a-subset-of-bundle-fields). + ## Vectors and Registers ### How do I create a Vector of Registers? diff --git a/docs/src/cookbooks/dataview.md b/docs/src/cookbooks/dataview.md new file mode 100644 index 00000000..ed969ca1 --- /dev/null +++ b/docs/src/cookbooks/dataview.md @@ -0,0 +1,179 @@ +--- +layout: docs +title: "DataView Cookbook" +section: "chisel3" +--- + +# DataView Cookbook + +* [How do I view a Data as a UInt or vice versa?](#how-do-i-view-a-data-as-a-uint-or-vice-versa) +* [How do I create a DataView for a Bundle has a type parameter?](#how-do-i-create-a-dataview-for-a-bundle-has-a-type-parameter) +* [How do I create a DataView for a Bundle with optional fields?](#how-do-i-create-a-dataview-for-a-bundle-with-optional-fields) +* [How do I connect a subset of Bundle fields?](#how-do-i-connect-a-subset-of-bundle-fields) + * [How do I view a Bundle as a parent type (superclass)?](#how-do-i-view-a-bundle-as-a-parent-type-superclass) + * [How do I view a Bundle as a parent type when the parent type is abstract (like a trait)?](#how-do-i-view-a-bundle-as-a-parent-type-when-the-parent-type-is-abstract-like-a-trait) + +## How do I view a Data as a UInt or vice versa? + +Subword viewing (using concatenations or bit extractions in `DataViews`) is not yet supported. +We intend to implement this in the future, but for the time being, use regular casts +(`.asUInt` and `.asTypeOf`). + +## How do I create a DataView for a Bundle has a type parameter? + +Instead of using a `val`, use a `def` which can have type parameters: + +```scala mdoc:silent:reset +import chisel3._ +import chisel3.experimental.dataview._ + +class Foo[T <: Data](val foo: T) extends Bundle +class Bar[T <: Data](val bar: T) extends Bundle + +object Foo { + implicit def view[T <: Data]: DataView[Foo[T], Bar[T]] = { + DataView(f => new Bar(f.foo.cloneType), _.foo -> _.bar) + // .cloneType is necessary because the f passed to this function will be bound hardware + } +} +``` + +```scala mdoc:invisible +// Make sure this works during elaboration, not part of doc +class MyModule extends RawModule { + val in = IO(Input(new Foo(UInt(8.W)))) + val out = IO(Output(new Bar(UInt(8.W)))) + out := in.viewAs[Bar[UInt]] +} +chisel3.stage.ChiselStage.emitVerilog(new MyModule) +``` +If you think about type parameterized classes as really being a family of different classes +(one for each type parameter), you can think about the `implicit def` as a generator of `DataViews` +for each type parameter. + +## How do I create a DataView for a Bundle with optional fields? + +Instead of using the default `DataView` apply method, use `DataView.mapping`: + +```scala mdoc:silent:reset +import chisel3._ +import chisel3.experimental.dataview._ + +class Foo(val w: Option[Int]) extends Bundle { + val foo = UInt(8.W) + val opt = w.map(x => UInt(x.W)) +} +class Bar(val w: Option[Int]) extends Bundle { + val bar = UInt(8.W) + val opt = w.map(x => UInt(x.W)) +} + +object Foo { + implicit val view: DataView[Foo, Bar] = + DataView.mapping( + // First argument is always the function to make the view from the target + f => new Bar(f.w), + // Now instead of a varargs of tuples of individual mappings, we have a single function that + // takes a target and a view and returns an Iterable of tuple + (f, b) => List(f.foo -> b.bar) ++ f.opt.map(_ -> b.opt.get) + // ^ Note that we can append options since they are Iterable! + + ) +} +``` + +```scala mdoc:invisible +// Make sure this works during elaboration, not part of doc +class MyModule extends RawModule { + val in = IO(Input(new Foo(Some(8)))) + val out = IO(Output(new Bar(Some(8)))) + out := in.viewAs[Bar] +} +chisel3.stage.ChiselStage.emitVerilog(new MyModule) +``` + +## How do I connect a subset of Bundle fields? + +Chisel 3 requires types to match exactly for connections. +DataView provides a mechanism for "viewing" one `Bundle` object as if it were the type of another, +which allows them to be connected. + +### How do I view a Bundle as a parent type (superclass)? + +For viewing `Bundles` as the type of the parent, it is as simple as using `viewAsSupertype` and providing a +template object of the parent type: + +```scala mdoc:silent:reset +import chisel3._ +import chisel3.experimental.dataview._ + +class Foo extends Bundle { + val foo = UInt(8.W) +} +class Bar extends Foo { + val bar = UInt(8.W) +} +class MyModule extends Module { + val foo = IO(Input(new Foo)) + val bar = IO(Output(new Bar)) + bar.viewAsSupertype(new Foo) := foo // bar.foo := foo.foo + bar.bar := 123.U // all fields need to be connected +} +``` +```scala mdoc:verilog +chisel3.stage.ChiselStage.emitVerilog(new MyModule) +``` + +### How do I view a Bundle as a parent type when the parent type is abstract (like a trait)? + +Given the following `Bundles` that share a common `trait`: + +```scala mdoc:silent:reset +import chisel3._ +import chisel3.experimental.dataview._ + +trait Super extends Bundle { + def bitwidth: Int + val a = UInt(bitwidth.W) +} +class Foo(val bitwidth: Int) extends Super { + val foo = UInt(8.W) +} +class Bar(val bitwidth: Int) extends Super { + val bar = UInt(8.W) +} +``` + +`Foo` and `Bar` cannot be connected directly, but they could be connected by viewing them both as if +they were instances of their common supertype, `Super`. +A straightforward approach might run into an issue like the following: + +```scala mdoc:fail +class MyModule extends Module { + val foo = IO(Input(new Foo(8))) + val bar = IO(Output(new Bar(8))) + bar.viewAsSupertype(new Super) := foo.viewAsSupertype(new Super) +} +``` + +The problem is that `viewAs` requires an object to use as a type template (so that it can be cloned), +but `traits` are abstract and cannot be instantiated. +The solution is to create an instance of an _anonymous class_ and use that object as the argument to `viewAs`. +We can do this like so: + +```scala mdoc:silent +class MyModule extends Module { + val foo = IO(Input(new Foo(8))) + val bar = IO(Output(new Bar(8))) + val tpe = new Super { // Adding curly braces creates an anonymous class + def bitwidth = 8 // We must implement any abstract methods + } + bar.viewAsSupertype(tpe) := foo.viewAsSupertype(tpe) +} +``` +By adding curly braces after the name of the trait, we're telling Scala to create a new concrete +subclass of the trait, and create an instance of it. +As indicated in the comment, abstract methods must still be implemented. +This is the same that happens when one writes `new Bundle {}`, +the curly braces create a new concrete subclass; however, because `Bundle` has no abstract methods, +the contents of the body can be empty. diff --git a/docs/src/explanations/dataview.md b/docs/src/explanations/dataview.md new file mode 100644 index 00000000..2f229bfc --- /dev/null +++ b/docs/src/explanations/dataview.md @@ -0,0 +1,520 @@ +--- +layout: docs +title: "DataView" +section: "chisel3" +--- + +# DataView + +_New in Chisel 3.5_ + +```scala mdoc:invisible +import chisel3._ +import chisel3.stage.ChiselStage.emitVerilog +``` + +## Introduction + +DataView is a mechanism for "viewing" Scala objects as a subtype of `chisel3.Data`. +Often, this is useful for viewing one subtype of `chisel3.Data`, as another. +One can think about a `DataView` as a mapping from a _Target_ type `T` to a _View_ type `V`. +This is similar to a cast (eg. `.asTypeOf`) with a few differences: +1. Views are _connectable_—connections to the view will occur on the target +2. Whereas casts are _structural_ (a reinterpretation of the underlying bits), a DataView is a customizable mapping +3. Views can be _partial_—not every field in the target must be included in the mapping + +## A Motivating Example (AXI4) + +[AXI4](https://en.wikipedia.org/wiki/Advanced_eXtensible_Interface) is a common interface in digital +design. +A typical Verilog peripheral using AXI4 will define a write channel as something like: +```verilog +module my_module( + // Write Channel + input AXI_AWVALID, + output AXI_AWREADY, + input [3:0] AXI_AWID, + input [19:0] AXI_AWADDR, + input [1:0] AXI_AWLEN, + input [1:0] AXI_AWSIZE, + // ... +); +``` + +This would correspond to the following Chisel Bundle: + +```scala mdoc +class VerilogAXIBundle(val addrWidth: Int) extends Bundle { + val AWVALID = Output(Bool()) + val AWREADY = Input(Bool()) + val AWID = Output(UInt(4.W)) + val AWADDR = Output(UInt(addrWidth.W)) + val AWLEN = Output(UInt(2.W)) + val AWSIZE = Output(UInt(2.W)) + // The rest of AW and other AXI channels here +} + +// Instantiated as +class my_module extends RawModule { + val AXI = IO(new VerilogAXIBundle(20)) +} +``` + +Expressing something that matches a standard Verilog interface is important when instantiating Verilog +modules in a Chisel design as `BlackBoxes`. +Generally though, Chisel developers prefer to use composition via utilities like `Decoupled` rather +than a flat handling of `ready` and `valid` as in the above. +A more "Chisel-y" implementation of this interface might look like: + +```scala mdoc +// Note that both the AW and AR channels look similar and could use the same Bundle definition +class AXIAddressChannel(val addrWidth: Int) extends Bundle { + val id = UInt(4.W) + val addr = UInt(addrWidth.W) + val len = UInt(2.W) + val size = UInt(2.W) + // ... +} +import chisel3.util.Decoupled +// We can compose the various AXI channels together +class AXIBundle(val addrWidth: Int) extends Bundle { + val aw = Decoupled(new AXIAddressChannel(addrWidth)) + // val ar = new AXIAddressChannel + // ... Other channels here ... +} +// Instantiated as +class MyModule extends RawModule { + val axi = IO(new AXIBundle(20)) +} +``` + +Of course, this would result in very different looking Verilog: + +```scala mdoc:verilog +emitVerilog(new MyModule { + override def desiredName = "MyModule" + axi := DontCare // Just to generate Verilog in this stub +}) +``` + +So how can we use our more structured types while maintaining expected Verilog interfaces? +Meet DataView: + +```scala mdoc +import chisel3.experimental.dataview._ + +// We recommend putting DataViews in a companion object of one of the involved types +object AXIBundle { + // Don't be afraid of the use of implicits, we will discuss this pattern in more detail later + implicit val axiView = DataView[VerilogAXIBundle, AXIBundle]( + // The first argument is a function constructing an object of View type (AXIBundle) + // from an object of the Target type (VerilogAXIBundle) + vab => new AXIBundle(vab.addrWidth), + // The remaining arguments are a mapping of the corresponding fields of the two types + _.AWVALID -> _.aw.valid, + _.AWREADY -> _.aw.ready, + _.AWID -> _.aw.bits.id, + _.AWADDR -> _.aw.bits.addr, + _.AWLEN -> _.aw.bits.len, + _.AWSIZE -> _.aw.bits.size, + // ... + ) +} +``` + +This `DataView` is a mapping between our flat, Verilog-style AXI Bundle to our more compositional, +Chisel-style AXI Bundle. +It allows us to define our ports to match the expected Verilog interface, while manipulating it as if +it were the more structured type: + +```scala mdoc +class AXIStub extends RawModule { + val AXI = IO(new VerilogAXIBundle(20)) + val view = AXI.viewAs[AXIBundle] + + // We can now manipulate `AXI` via `view` + view.aw.bits := 0.U.asTypeOf(new AXIAddressChannel(20)) // zero everything out by default + view.aw.valid := true.B + when (view.aw.ready) { + view.aw.bits.id := 5.U + view.aw.bits.addr := 1234.U + // We can still manipulate AXI as well + AXI.AWLEN := 1.U + } +} +``` + +This will generate Verilog that matches the standard naming convention: + +```scala mdoc:verilog +emitVerilog(new AXIStub) +``` + +Note that if both the _Target_ and the _View_ types are subtypes of `Data` (as they are in this example), +the `DataView` is _invertible_. +This means that we can easily create a `DataView[AXIBundle, VerilogAXIBundle]` from our existing +`DataView[VerilogAXIBundle, AXIBundle]`, all we need to do is provide a function to construct +a `VerilogAXIBundle` from an instance of an `AXIBundle`: + +```scala mdoc:silent +// Note that typically you should define these together (eg. inside object AXIBundle) +implicit val axiView2 = AXIBundle.axiView.invert(ab => new VerilogAXIBundle(ab.addrWidth)) +``` + +The following example shows this and illustrates another use case of `DataView`—connecting unrelated +types: + +```scala mdoc +class ConnectionExample extends RawModule { + val in = IO(new AXIBundle(20)) + val out = IO(Flipped(new VerilogAXIBundle(20))) + out.viewAs[AXIBundle] <> in +} +``` + +This results in the corresponding fields being connected in the emitted Verilog: + +```scala mdoc:verilog +emitVerilog(new ConnectionExample) +``` + +## Other Use Cases + +While the ability to map between `Bundle` types as in the AXI4 example is pretty compelling, +DataView has many other applications. +Importantly, because the _Target_ of the `DataView` need not be a `Data`, it provides a way to use +`non-Data` objects with APIs that require `Data`. + +### Tuples + +Perhaps the most helpful use of `DataView` for a non-`Data` type is viewing Scala tuples as `Bundles`. +For example, in Chisel prior to the introduction of `DataView`, one might try to `Mux` tuples and +see an error like the following: + + + +```scala mdoc:fail +class TupleExample extends RawModule { + val a, b, c, d = IO(Input(UInt(8.W))) + val cond = IO(Input(Bool())) + val x, y = IO(Output(UInt(8.W))) + (x, y) := Mux(cond, (a, b), (c, d)) +} +``` + +The issue, is that Chisel primitives like `Mux` and `:=` only operate on subtypes of `Data` and +Tuples (as members of the Scala standard library), are not subclasses of `Data`. +`DataView` provides a mechanism to _view_ a `Tuple` as if it were a `Data`: + + + +```scala mdoc:invisible +// ProductDataProduct +implicit val productDataProduct: DataProduct[Product] = new DataProduct[Product] { + def dataIterator(a: Product, path: String): Iterator[(Data, String)] = { + a.productIterator.zipWithIndex.collect { case (d: Data, i) => d -> s"$path._$i" } + } +} +``` + +```scala mdoc +// We need a type to represent the Tuple +class HWTuple2[A <: Data, B <: Data](val _1: A, val _2: B) extends Bundle + +// Provide DataView between Tuple and HWTuple +implicit def view[A <: Data, B <: Data]: DataView[(A, B), HWTuple2[A, B]] = + DataView(tup => new HWTuple2(tup._1.cloneType, tup._2.cloneType), + _._1 -> _._1, _._2 -> _._2) +``` + +Now, we can use `.viewAs` to view Tuples as if they were subtypes of `Data`: + +```scala mdoc +class TupleVerboseExample extends RawModule { + val a, b, c, d = IO(Input(UInt(8.W))) + val cond = IO(Input(Bool())) + val x, y = IO(Output(UInt(8.W))) + (x, y).viewAs[HWTuple2[UInt, UInt]] := Mux(cond, (a, b).viewAs[HWTuple2[UInt, UInt]], (c, d).viewAs[HWTuple2[UInt, UInt]]) +} +``` + +This is much more verbose than the original idea of just using the Tuples directly as if they were `Data`. +We can make this better by providing an implicit conversion that views a `Tuple` as a `HWTuple2`: + +```scala mdoc +implicit def tuple2hwtuple[A <: Data, B <: Data](tup: (A, B)): HWTuple2[A, B] = + tup.viewAs[HWTuple2[A, B]] +``` + +Now, the original code just works! + +```scala mdoc +class TupleExample extends RawModule { + val a, b, c, d = IO(Input(UInt(8.W))) + val cond = IO(Input(Bool())) + val x, y = IO(Output(UInt(8.W))) + (x, y) := Mux(cond, (a, b), (c, d)) +} +``` + +```scala mdoc:invisible +// Always emit Verilog to make sure it actually works +emitVerilog(new TupleExample) +``` + +Note that this example ignored `DataProduct` which is another required piece (see [the documentation +about it below](#dataproduct)). + +All of this is slated to be included the Chisel standard library. + +## Totality and PartialDataView + +A `DataView` is _total_ if all fields of the _Target_ type and all fields of the _View_ type are +included in the mapping. +Chisel will error if a field is accidentally left out from a `DataView`. +For example: + +```scala mdoc +class BundleA extends Bundle { + val foo = UInt(8.W) + val bar = UInt(8.W) +} +class BundleB extends Bundle { + val fizz = UInt(8.W) +} +``` + +```scala mdoc:crash +{ // Using an extra scope here to avoid a bug in mdoc (documentation generation) +// We forgot BundleA.foo in the mapping! +implicit val myView = DataView[BundleA, BundleB](_ => new BundleB, _.bar -> _.fizz) +class BadMapping extends Module { + val in = IO(Input(new BundleA)) + val out = IO(Output(new BundleB)) + out := in.viewAs[BundleB] +} +// We must run Chisel to see the error +emitVerilog(new BadMapping) +} +``` + +As that error suggests, if we *want* the view to be non-total, we can use a `PartialDataView`: + +```scala mdoc +// A PartialDataView does not have to be total for the Target +implicit val myView = PartialDataView[BundleA, BundleB](_ => new BundleB, _.bar -> _.fizz) +class PartialDataViewModule extends Module { + val in = IO(Input(new BundleA)) + val out = IO(Output(new BundleB)) + out := in.viewAs[BundleB] +} +``` + +```scala mdoc:verilog +emitVerilog(new PartialDataViewModule) +``` + +While `PartialDataViews` need not be total for the _Target_, both `PartialDataViews` and `DataViews` +must always be total for the _View_. +This has the consequence that `PartialDataViews` are **not** invertible in the same way as `DataViews`. + +For example: + +```scala mdoc:crash +{ // Using an extra scope here to avoid a bug in mdoc (documentation generation) +implicit val myView2 = myView.invert(_ => new BundleA) +class PartialDataViewModule2 extends Module { + val in = IO(Input(new BundleA)) + val out = IO(Output(new BundleB)) + // Using the inverted version of the mapping + out.viewAs[BundleA] := in +} +// We must run Chisel to see the error +emitVerilog(new PartialDataViewModule2) +} +``` + +As noted, the mapping must **always** be total for the `View`. + +## Advanced Details + +`DataView` takes advantage of features of Scala that may be new to many users of Chisel—in particular +[Type Classes](#type-classes). + +### Type Classes + +[Type classes](https://en.wikipedia.org/wiki/Type_class) are powerful language feature for writing +polymorphic code. +They are a common feature in "modern programming languages" like +Scala, +Swift (see [protocols](https://docs.swift.org/swift-book/LanguageGuide/Protocols.html)), +and Rust (see [traits](https://doc.rust-lang.org/book/ch10-02-traits.html)). +Type classes may appear similar to inheritance in object-oriented programming but there are some +important differences: + +1. You can provide a type class for a type you don't own (eg. one defined in a 3rd party library, + the Scala standard library, or Chisel itself) +2. You can write a single type class for many types that do not have a sub-typing relationship +3. You can provide multiple different type classes for the same type + +For `DataView`, (1) is crucial because we want to be able to implement `DataViews` of built-in Scala +types like tuples and `Seqs`. Furthermore, `DataView` has two type parameters (the _Target_ and the +_View_ types) so inheritance does not really make sense—which type would `extend` `DataView`? + +In Scala 2, type classes are not a built-in language feature, but rather are implemented using implicits. +There are great resources out there for interested readers: +* [Basic Tutorial](https://scalac.io/blog/typeclasses-in-scala/) +* [Fantastic Explanation on StackOverflow](https://stackoverflow.com/a/5598107/2483329) + +Note that Scala 3 has added built-in syntax for type classes that does not apply to Chisel 3 which +currently only supports Scala 2. + +### Implicit Resolution + +Given that `DataView` is implemented using implicits, it is important to understand implicit +resolution. +Whenever the compiler sees an implicit argument is required, it first looks in _current scope_ +before looking in the _implicit scope_. + +1. Current scope + * Values defined in the current scope + * Explicit imports + * Wildcard imports +2. Implicit scope + * Companion object of a type + * Implicit scope of an argument's type + * Implicit scope of type parameters + +If at either stage, multiple implicits are found, then the static overloading rule is used to resolve +it. +Put simply, if one implicit applies to a more-specific type than the other, the more-specific one +will be selected. +If multiple implicits apply within a given stage, then the compiler throws an ambiguous implicit +resolution error. + + +This section draws heavily from [[1]](https://stackoverflow.com/a/5598107/2483329) and +[[2]](https://stackoverflow.com/a/5598107/2483329). +In particular, see [1] for examples. + +#### Implicit Resolution Example + +To help clarify a bit, let us consider how implicit resolution works for `DataView`. +Consider the definition of `viewAs`: + +```scala +def viewAs[V <: Data](implicit dataView: DataView[T, V]): V +``` + +Armed with the knowledge from the previous section, we know that whenever we call `.viewAs`, the +Scala compiler will first look for a `DataView[T, V]` in the current scope (defined in, or imported), +then it will look in the companion objects of `DataView`, `T`, and `V`. +This enables a fairly powerful pattern, namely that default or typical implementations of a `DataView` +should be defined in the companion object for one of the two types. +We can think about `DataViews` defined in this way as "low priority defaults". +They can then be overruled by a specific import if a given user ever wants different behavior. +For example: + +Given the following types: + +```scala mdoc +class Foo extends Bundle { + val a = UInt(8.W) + val b = UInt(8.W) +} +class Bar extends Bundle { + val c = UInt(8.W) + val d = UInt(8.W) +} +object Foo { + implicit val f2b = DataView[Foo, Bar](_ => new Bar, _.a -> _.c, _.b -> _.d) + implicit val b2f = f2b.invert(_ => new Foo) +} +``` + +This provides an implementation of `DataView` in the _implicit scope_ as a "default" mapping between +`Foo` and `Bar` (and it doesn't even require an import!): + +```scala mdoc +class FooToBar extends Module { + val foo = IO(Input(new Foo)) + val bar = IO(Output(new Bar)) + bar := foo.viewAs[Bar] +} +``` + +```scala mdoc:verilog +emitVerilog(new FooToBar) +``` + +However, it's possible that some user of `Foo` and `Bar` wants different behavior, +perhaps they would prefer more of "swizzling" behavior rather than a direct mapping: + +```scala mdoc +object Swizzle { + implicit val swizzle = DataView[Foo, Bar](_ => new Bar, _.a -> _.d, _.b -> _.c) +} +// Current scope always wins over implicit scope +import Swizzle._ +class FooToBarSwizzled extends Module { + val foo = IO(Input(new Foo)) + val bar = IO(Output(new Bar)) + bar := foo.viewAs[Bar] +} +``` + +```scala mdoc:verilog +emitVerilog(new FooToBarSwizzled) +``` + +### DataProduct + +`DataProduct` is a type class used by `DataView` to validate the correctness of a user-provided mapping. +In order for a type to be "viewable" (ie. the `Target` type of a `DataView`), it must have an +implementation of `DataProduct`. + +For example, say we have some non-Bundle type: +```scala mdoc +// Loosely based on chisel3.util.Counter +class MyCounter(val width: Int) { + /** Indicates if the Counter is incrementing this cycle */ + val active = WireDefault(false.B) + val value = RegInit(0.U(width.W)) + def inc(): Unit = { + active := true.B + value := value + 1.U + } + def reset(): Unit = { + value := 0.U + } +} +``` + +Say we want to view `MyCounter` as a `Valid[UInt]`: + +```scala mdoc:fail +import chisel3.util.Valid +implicit val counterView = DataView[MyCounter, Valid[UInt]](c => Valid(UInt(c.width.W)), _.value -> _.bits, _.active -> _.valid) +``` + +As you can see, this fails Scala compliation. +We need to provide an implementation of `DataProduct[MyCounter]` which provides Chisel a way to access +the objects of type `Data` within `MyCounter`: + +```scala mdoc:silent +import chisel3.util.Valid +implicit val counterProduct = new DataProduct[MyCounter] { + // The String part of the tuple is a String path to the object to help in debugging + def dataIterator(a: MyCounter, path: String): Iterator[(Data, String)] = + List(a.value -> s"$path.value", a.active -> s"$path.active").iterator +} +// Now this works +implicit val counterView = DataView[MyCounter, Valid[UInt]](c => Valid(UInt(c.width.W)), _.value -> _.bits, _.active -> _.valid) +``` + +Why is this useful? +This is how Chisel is able to check for totality as [described above](#totality-and-partialdataview). +In addition to checking if a user has left a field out of the mapping, it also allows Chisel to check +if the user has included a `Data` in the mapping that isn't actually a part of the _target_ nor the +_view_. + -- cgit v1.2.3 From e14bcb145860207a825f780e3d0984e869f605c9 Mon Sep 17 00:00:00 2001 From: Jack Koenig Date: Tue, 17 Aug 2021 14:24:20 -0700 Subject: [docs] Add example of stripping directions from type (#2074) * [docs] Add example of stripping directions from type * Apply suggestions from code review Co-authored-by: Megan Wachs * Improve := comment Co-authored-by: Megan Wachs Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>--- docs/src/cookbooks/cookbook.md | 54 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) (limited to 'docs') diff --git a/docs/src/cookbooks/cookbook.md b/docs/src/cookbooks/cookbook.md index f033c285..cff7a5b2 100644 --- a/docs/src/cookbooks/cookbook.md +++ b/docs/src/cookbooks/cookbook.md @@ -27,6 +27,8 @@ Please note that these examples make use of [Chisel's scala-style printing](../e * [How do I get Chisel to name signals properly in blocks like when/withClockAndReset?](#how-do-i-get-chisel-to-name-signals-properly-in-blocks-like-whenwithclockandreset) * [How do I get Chisel to name the results of vector reads properly?](#how-do-i-get-chisel-to-name-the-results-of-vector-reads-properly) * [How can I dynamically set/parametrize the name of a module?](#how-can-i-dynamically-setparametrize-the-name-of-a-module) +* Directionality + * [How do I strip directions from a bidirectional Bundle (or other Data)?](#how-do-i-strip-directions-from-a-bidirectional-bundle-or-other-data) ## Type Conversions @@ -462,3 +464,55 @@ ChiselStage.emitVerilog(new Salt) ```scala mdoc:verilog ChiselStage.emitVerilog(new Salt) ``` + +## Directionality + +### How do I strip directions from a bidirectional Bundle (or other Data)? + +Given a bidirectional port like a `Decoupled`, you will get an error if you try to connect it directly +to a register: + +```scala mdoc:silent +import chisel3.util.Decoupled +class BadRegConnect extends Module { + val io = IO(new Bundle { + val enq = Decoupled(UInt(8.W)) + }) + + val monitor = Reg(chiselTypeOf(io.enq)) + monitor := io.enq +} +``` + +```scala mdoc:crash +ChiselStage.emitVerilog(new BadRegConnect) +``` + +While there is no construct to "strip direction" in Chisel3, wrapping a type in `Output(...)` +(the default direction in Chisel3) will +set all of the individual elements to output direction. +This will have the desired result when used to construct a Register: + +```scala mdoc:silent +import chisel3.util.Decoupled +class CoercedRegConnect extends Module { + val io = IO(new Bundle { + val enq = Flipped(Decoupled(UInt(8.W))) + }) + + // Make a Reg which contains all of the bundle's signals, regardless of their directionality + val monitor = Reg(Output(chiselTypeOf(io.enq))) + // Even though io.enq is bidirectional, := will drive all fields of monitor with the fields of io.enq + monitor := io.enq +} +``` + + +```scala mdoc:invisible +ChiselStage.emitVerilog(new CoercedRegConnect { + // Provide default connections that would just muddy the example + io.enq.ready := true.B + // dontTouch so that it shows up in the Verilog + dontTouch(monitor) +}) +``` -- cgit v1.2.3 From f50ce19406e45982390162777fb62c8563c962c7 Mon Sep 17 00:00:00 2001 From: anniej-sifive Date: Mon, 23 Aug 2021 14:37:09 -0700 Subject: Add multiple dimensions to VecInit fill and iterate (#2065) Co-authored-by: Jack Koenig --- docs/src/cookbooks/cookbook.md | 46 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'docs') diff --git a/docs/src/cookbooks/cookbook.md b/docs/src/cookbooks/cookbook.md index cff7a5b2..ce49b668 100644 --- a/docs/src/cookbooks/cookbook.md +++ b/docs/src/cookbooks/cookbook.md @@ -17,6 +17,7 @@ Please note that these examples make use of [Chisel's scala-style printing](../e * [How do I create a UInt from a Vec of Bool?](#how-do-i-create-a-uint-from-a-vec-of-bool) * [How do I connect a subset of Bundle fields?](#how-do-i-connect-a-subset-of-bundle-fields) * Vectors and Registers + * [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 create a finite state machine?](#how-do-i-create-a-finite-state-machine-fsm) @@ -157,6 +158,51 @@ See the [DataView cookbook](dataview#how-do-i-connect-a-subset-of-bundle-fields) ## Vectors and Registers +### Can I make a 2D or 3D Vector? + +Yes. Using `VecInit` you can make Vectors that hold Vectors of Chisel types. Methods `fill` and `tabulate` make these multi-dimensional Vectors. + +```scala mdoc:silent:reset +import chisel3._ + +class MyBundle extends Bundle { + val foo = UInt(4.W) + val bar = UInt(4.W) +} + +class Foo extends Module { + //2D Fill + val twoDVec = VecInit.fill(2, 3)(5.U) + //3D Fill + val myBundle = Wire(new MyBundle) + myBundle.foo := 0xc.U + myBundle.bar := 0x3.U + val threeDVec = VecInit.fill(1, 2, 3)(myBundle) + assert(threeDVec(0)(0)(0).foo === 0xc.U && threeDVec(0)(0)(0).bar === 0x3.U) + + //2D Tabulate + val indexTiedVec = VecInit.tabulate(2, 2){ (x, y) => (x + y).U } + assert(indexTiedVec(0)(0) === 0.U) + assert(indexTiedVec(0)(1) === 1.U) + assert(indexTiedVec(1)(0) === 1.U) + assert(indexTiedVec(1)(1) === 2.U) + //3D Tabulate + val indexTiedVec3D = VecInit.tabulate(2, 3, 4){ (x, y, z) => (x + y * z).U } + assert(indexTiedVec3D(0)(0)(0) === 0.U) + assert(indexTiedVec3D(1)(1)(1) === 2.U) + assert(indexTiedVec3D(1)(1)(2) === 3.U) + assert(indexTiedVec3D(1)(1)(3) === 4.U) + assert(indexTiedVec3D(1)(2)(3) === 7.U) +} +``` +```scala mdoc:invisible +// Hidden but will make sure this actually compiles +import chisel3.stage.ChiselStage + +ChiselStage.emitVerilog(new Foo) +``` + + ### How do I create a Vector of Registers? **Rule! Use Reg of Vec not Vec of Reg!** -- cgit v1.2.3 From 9fa8da227569455a77596355aeb114f9c164510a Mon Sep 17 00:00:00 2001 From: Adam Izraelevitz Date: Sun, 5 Sep 2021 12:11:32 -0700 Subject: Add Definition and Instance API (#2045) This introduces a new experimental API for module instantiation that disentagles elaborating the definition (or implementation) from instantiation of a given module. This solves Chisel's longstanding reliance on "Deduplication" for generating Verilog with multiple instances of the same module. The new API resides in package chisel3.experimental.hierarchy. Please see the hierarchy ScalaDoc, documentation, and tests for examples of use. Co-authored-by: Jack Koenig Co-authored-by: Megan Wachs Co-authored-by: Schuyler Eldridge --- docs/src/cookbooks/hierarchy.md | 204 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 docs/src/cookbooks/hierarchy.md (limited to 'docs') diff --git a/docs/src/cookbooks/hierarchy.md b/docs/src/cookbooks/hierarchy.md new file mode 100644 index 00000000..91d99aa6 --- /dev/null +++ b/docs/src/cookbooks/hierarchy.md @@ -0,0 +1,204 @@ +--- +layout: docs +title: "Hierarchy Cookbook" +section: "chisel3" +--- + +# Hierarchy Cookbook + +* [How do I instantiate multiple instances with the same module parameterization, but avoid re-elaboration?](#how-do-i-instantiate-multiple-instances-with-the-same-module-parameterization) +* [How do I access internal fields of an instance?](#how-do-i-access-internal-fields-of-an-instance) +* [How do I make my parameters accessable from an instance?](#how-do-i-make-my-parameters-accessable-from-an-instance) +* [How do I reuse a previously elaborated module, if my new module has the same parameterization?](#how-do-i-reuse-a-previously-elaborated-module-if-my-new-module-has-the-same-parameterization) + +## How do I instantiate multiple instances with the same module parameterization? + +Prior to this package, Chisel users relied on deduplication in a FIRRTL compiler to combine +structurally equivalent modules into one module (aka "deduplication"). +This package introduces the following new APIs to enable multiply-instantiated modules directly in Chisel. + +`Definition(...)` enables elaborating a module, but does not actually instantiate that module. +Instead, it returns a `Definition` class which represents that module's definition. + +`Instance(...)` takes a `Definition` and instantiates it, returning an `Instance` object. + +Modules (classes or traits) which will be used with the `Definition`/`Instance` api should be marked +with the `@instantiable` annotation at the class/trait definition. + +To make a Module's members variables accessible from an `Instance` object, they must be annotated +with the `@public` annotation. Note that this is only accessible from a Scala sense—this is not +in and of itself a mechanism for cross-module references. + +In the following example, use `Definition`, `Instance`, `@instantiable` and `@public` to create +multiple instances of one specific parameterization of a module, `AddOne`. + +```scala mdoc:silent +import chisel3._ +import chisel3.experimental.hierarchy.{Definition, Instance, instantiable, public} + +@instantiable +class AddOne(width: Int) extends Module { + @public val in = IO(Input(UInt(width.W))) + @public val out = IO(Output(UInt(width.W))) + out := in + 1.U +} + +class AddTwo(width: Int) extends Module { + val in = IO(Input(UInt(width.W))) + val out = IO(Output(UInt(width.W))) + val addOneDef = Definition(new AddOne(width)) + val i0 = Instance(addOneDef) + val i1 = Instance(addOneDef) + i0.in := in + i1.in := i0.out + out := i1.out +} +``` +```scala mdoc:verilog +chisel3.stage.ChiselStage.emitVerilog(new AddTwo(10)) +``` + +## How do I access internal fields of an instance? + +You can mark internal members of a class or trait marked with `@instantiable` with the `@public` annotation. +The requirements are that the field is publicly accessible, is a `val` or `lazy val`, and is a valid type. +The list of valid types are: + +1. `IsInstantiable` +2. `IsLookupable` +3. `Data` +4. `BaseModule` +5. `Iterable`/`Option `containing a type that meets these requirements +6. Basic type like `String`, `Int`, `BigInt` etc. + +To mark a superclass's member as `@public`, use the following pattern (shown with `val clock`). + +```scala mdoc:silent:reset +import chisel3._ +import chisel3.experimental.hierarchy.{instantiable, public} + +@instantiable +class MyModule extends Module { + @public val clock = clock +} +``` + +You'll get the following error message for improperly marking something as `@public`: + +```scala mdoc:reset:fail +import chisel3._ +import chisel3.experimental.hierarchy.{instantiable, public} + +object NotValidType + +@instantiable +class MyModule extends Module { + @public val x = NotValidType +} +``` + +## How do I make my parameters accessible from an instance? + +If an instance's parameters are simple (e.g. `Int`, `String` etc.) they can be marked directly with `@public`. + +Often, parameters are more complicated and are contained in case classes. +In such cases, mark the case class with the `IsLookupable` trait. +This indicates to Chisel that instances of the `IsLookupable` class may be accessed from within instances. + +However, ensure that these parameters are true for **all** instances of a definition. +For example, if our parameters contained an id field which was instance-specific but defaulted to zero, +then the definition's id would be returned for all instances. +This change in behavior could lead to bugs if other code presumed the id field was correct. + +Thus, it is important that when converting normal modules to use this package, +you are careful about what you mark as `IsLookupable`. + +In the following example, we added the trait `IsLookupable` to allow the member to be marked `@public`. + +```scala mdoc:reset:silent +import chisel3._ +import chisel3.experimental.hierarchy.{Definition, Instance, instantiable, IsLookupable, public} + +case class MyCaseClass(width: Int) extends IsLookupable + +@instantiable +class MyModule extends Module { + @public val x = MyCaseClass(10) +} + +class Top extends Module { + val inst = Instance(Definition(new MyModule)) + println(s"Width is ${inst.x.width}") +} +``` +```scala mdoc:passthrough +println("```") +chisel3.stage.ChiselStage.elaborate(new Top) +println("```") +``` + +## How do I look up parameters from a Definition, if I don't want to instantiate it? + +Just like `Instance`s, `Definition`'s also contain accessors for `@public` members. +As such, you can directly access them: + +```scala mdoc:reset:silent +import chisel3._ +import chisel3.experimental.hierarchy.{Definition, instantiable, public} + +@instantiable +class AddOne(val width: Int) extends Module { + @public val width = width + @public val in = IO(Input(UInt(width.W))) + @public val out = IO(Output(UInt(width.W))) + out := in + 1.U +} + +class Top extends Module { + val definition = Definition(new AddOne(10)) + println(s"Width is: ${definition.width}") +} +``` +```scala mdoc:verilog +chisel3.stage.ChiselStage.emitVerilog(new Top()) +``` + +## How do I parameterize a module by its children instances? + +Prior to the introduction of this package, a parent module would have to pass all necessary parameters +when instantiating a child module. +This had the unfortunate consequence of requiring a parent's parameters to always contain the child's +parameters, which was an unnecessary coupling which lead to some anti-patterns. + +Now, a parent can take a child `Definition` as an argument, and instantiate it directly. +In addition, it can analyze the parameters used in the definition to parameterize itself. +In a sense, now the child can actually parameterize the parent. + +In the following example, we create a definition of `AddOne`, and pass the definition to `AddTwo`. +The width of the `AddTwo` ports are now derived from the parameterization of the `AddOne` instance. + +```scala mdoc:reset +import chisel3._ +import chisel3.experimental.hierarchy.{Definition, Instance, instantiable, public} + +@instantiable +class AddOne(val width: Int) extends Module { + @public val width = width + @public val in = IO(Input(UInt(width.W))) + @public val out = IO(Output(UInt(width.W))) + out := in + 1.U +} + +class AddTwo(addOneDef: Definition[AddOne]) extends Module { + val i0 = Instance(addOneDef) + val i1 = Instance(addOneDef) + val in = IO(Input(UInt(addOneDef.width.W))) + val out = IO(Output(UInt(addOneDef.width.W))) + i0.in := in + i1.in := i0.out + out := i1.out +} +``` +```scala mdoc:verilog +chisel3.stage.ChiselStage.emitVerilog(new AddTwo(Definition(new AddOne(10)))) +``` -- cgit v1.2.3