Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move more docs #1601

Merged
merged 10 commits into from
Oct 5, 2020
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,21 @@ import chisel3.internal.InstanceId

import firrtl._
import firrtl.annotations.{Annotation, SingleTargetAnnotation}
import firrtl.annotations.{CircuitName, ComponentName, ModuleName, Named}
import firrtl.annotations.{CircuitTarget, ModuleTarget, InstanceTarget, ReferenceTarget, Target}
```

### Define an `Annotation` and a `Transform`

First, define an `Annotation` that contains a string associated with a `Named` thing in the Chisel circuit.
First, define an `Annotation` that contains a string associated with a `Target` thing in the Chisel circuit.
This `InfoAnnotation` extends [`SingleTargetAnnotation`](https://www.chisel-lang.org/api/firrtl/1.2.0/firrtl/annotations/SingleTargetAnnotation.html), an `Annotation` associated with *one* thing in a FIRRTL circuit:

```scala mdoc:silent
/** An annotation that contains some string information */
case class InfoAnnotation(target: Named, info: String) extends SingleTargetAnnotation[Named] {
def duplicate(newTarget: Named) = this.copy(target = newTarget)
case class InfoAnnotation(target: Target, info: String) extends SingleTargetAnnotation[Target] {
def duplicate(newTarget: Target) = this.copy(target = newTarget)
}
```

> Note: `Named` is currently deprecated in favor of the more specific `Target`.
> Currently, `Named` is still the advised approach for writing `Annotation`s.

Second, define a `Transform` that consumes this `InfoAnnotation`.
This `InfoTransform` simply reads all annotations, prints any `InfoAnnotation`s it finds, and removes them.

Expand All @@ -61,13 +58,16 @@ class InfoTransform() extends Transform with DependencyAPIMigration {
println("Starting transform 'IdentityTransform'")

val annotationsx = state.annotations.flatMap{
case InfoAnnotation(a: CircuitName, info) =>
case InfoAnnotation(a: CircuitTarget, info) =>
println(s" - Circuit '${a.serialize}' annotated with '$info'")
None
case InfoAnnotation(a: ModuleName, info) =>
case InfoAnnotation(a: ModuleTarget, info) =>
println(s" - Module '${a.serialize}' annotated with '$info'")
None
case InfoAnnotation(a: ComponentName, info) =>
case InfoAnnotation(a: InstanceTarget, info) =>
println(s" - Instance '${a.serialize}' annotated with '$info'")
None
case InfoAnnotation(a: ReferenceTarget, info) =>
println(s" - Component '${a.serialize} annotated with '$info''")
None
case a =>
Expand Down Expand Up @@ -98,7 +98,7 @@ This annotator also mixes in the `RunFirrtlTransform` trait (abstract in the `tr
object InfoAnnotator {
def info(component: InstanceId, info: String): Unit = {
annotate(new ChiselAnnotation with RunFirrtlTransform {
def toFirrtl: Annotation = InfoAnnotation(component.toNamed, info)
def toFirrtl: Annotation = InfoAnnotation(component.toTarget, info)
def transformClass = classOf[InfoTransform]
})
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ Ports declared in the IO Bundle will be generated with the requested name (ie. n

### Parameterization

**This is an experimental feature and is subject to API change**

Verilog parameters can be passed as an argument to the BlackBox constructor.

For example, consider instantiating a Xilinx differential clock buffer (IBUFDS) in a Chisel design:
Expand Down Expand Up @@ -54,7 +52,8 @@ 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.
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 {
Expand All @@ -80,7 +79,7 @@ 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](annotations.md). 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
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.md). 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
class BlackBoxRealAdd extends BlackBox with HasBlackBoxResource {
val io = IO(new Bundle() {
Expand All @@ -91,13 +90,17 @@ class BlackBoxRealAdd extends BlackBox with HasBlackBoxResource {
setResource("/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 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
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
```

### 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
Expand All @@ -123,9 +126,22 @@ class BlackBoxRealAdd extends BlackBox with HasBlackBoxInline {
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 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 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.
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
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
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.

### The interpreter
The [firrtl interpreter](https://github.com/ucb-bar/firrtl-interpreter) uses a separate system that allows users to construct scala implementations of the black boxes. The scala implementation code built into a BlackBoxFactory which is 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.

***Note that the FIRRTL Interpreter is deprecated. Please use Treadle, the new Chisel/FIRRTL simulator***
The [firrtl interpreter](https://github.com/ucb-bar/firrtl-interpreter) uses a separate system that allows users to
construct scala implementations of the black boxes. The scala implementation code built into a BlackBoxFactory which is
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.
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,54 @@ 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
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 {
val sign = Bool()
val exponent = UInt(8.W)
val significand = UInt(23.W)
}

val x = Wire(new MyFloat)
val xs = x.sign
class ModuleWithFloatWire extends RawModule {
val x = Wire(new MyFloat)
val xs = x.sign
}
```

> 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.

```scala
// Floating point constant.
val floatConst = Wire(new MyFloat)
floatConst.sign := true.B
floatConst.exponent := 10.U
floatConst.significand := 128.U
> 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.

```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.

Vecs create an indexable vector of elements, and are constructed as
follows:
```scala
// Vector of 5 23-bit signed integers.
val myVec = Wire(Vec(5, SInt(23.W)))
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.
val myVec = Wire(Vec(5, SInt(23.W)))

// Connect to one element of vector.
val reg3 = myVec(3)
// Connect to one element of vector.
val reg3 = myVec(3)
}
```

(Note that we specify the number followed by the type of the `Vec` elements. We also specifiy the width of the `SInt`)
Expand All @@ -49,7 +63,7 @@ superclass, `Data`. Every object that ultimately inherits from

Bundles and Vecs can be arbitrarily nested to build complex data
structures:
```scala
```scala mdoc:silent
class BigBundle extends Bundle {
// Vector of 5 23-bit signed integers.
val myVec = Vec(5, SInt(23.W))
Expand All @@ -63,53 +77,48 @@ 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](functional-module-creation.md).
[Function Constructor](../wiki-deprecated/functional-module-creation.md).

### Flipping Bundles

The `Flipped()` function recursively flips all elements in a Bundle/Record. This is very useful for building bidirectional interfaces that connect to each other (e.g. `Decoupled`). See below for an example.

```scala
import chisel3.experimental.RawModule
class MyBundle extends Bundle {
```scala mdoc:silent
class ABBundle extends Bundle {
val a = Input(Bool())
val b = Output(Bool())
}
class MyModule extends RawModule {
class MyFlippedModule extends RawModule {
// Normal instantiation of the bundle
// 'a' is an Input and 'b' is an Output
val normalBundle = IO(new MyBundle)
val normalBundle = IO(new ABBundle)
normalBundle.b := normalBundle.a

// Flipped recursively flips the direction of all Bundle fields
// Now 'a' is an Output and 'b' is an Input
val flippedBundle = IO(Flipped(new MyBundle))
val flippedBundle = IO(Flipped(new ABBundle))
flippedBundle.a := flippedBundle.b
}
```

This generates the following Verilog:

```verilog
module MyModule( // @[:@3.2]
input normalBundle_a, // @[:@4.4]
output normalBundle_b, // @[:@4.4]
output flippedBundle_a, // @[:@5.4]
input flippedBundle_b // @[:@5.4]
);
assign normalBundle_b = normalBundle_a;
assign flippedBundle_a = flippedBundle_b;
endmodule
```scala mdoc
import chisel3.stage.ChiselStage

println(ChiselStage.emitVerilog(new MyFlippedModule()))
```

### MixedVec

(Chisel 3.2+)

All elements of a `Vec` must be of the same type. If we want to create a Vec where the elements have different types, we can use a MixedVec:
All elements of a `Vec` must be of the same type. If we want to create a Vec where the elements have different types, we
can use a MixedVec:

```scala
class MyModule extends Module {
```scala mdoc:silent
import chisel3.util.MixedVec
class ModuleMixedVec extends Module {
val io = IO(new Bundle {
val x = Input(UInt(3.W))
val y = Input(UInt(10.W))
Expand All @@ -122,8 +131,8 @@ class MyModule extends Module {

We can also programmatically create the types in a MixedVec:

```scala
class MyModule(x: Int, y: Int) extends Module {
```scala mdoc:silent
class ModuleProgrammaticMixedVec(x: Int, y: Int) extends Module {
val io = IO(new Bundle {
val vec = Input(MixedVec((x to y) map { i => UInt(i.W) }))
// ...
Expand All @@ -134,12 +143,16 @@ class MyModule(x: Int, y: Int) extends Module {

### A note on `cloneType`

Since Chisel is built on top of Scala and the JVM, it needs to know how to construct copies of bundles for various purposes (creating wires, IOs, etc). If you have a parametrized bundle and Chisel can't automatically figure out how to clone your bundle, you will need to create a custom `cloneType` method in your bundle. Most of the time, this is as simple as `override def cloneType = (new YourBundleHere(...)).asInstanceOf[this.type]`.
Since Chisel is built on top of Scala and the JVM, it needs to know how to construct copies of bundles for various
purposes (creating wires, IOs, etc). If you have a parametrized bundle and Chisel can't automatically figure out how to
clone your bundle, you will need to create a custom `cloneType` method in your bundle. Most of the time, this is as
simple as `override def cloneType = (new YourBundleHere(...)).asInstanceOf[this.type]`.

Note that in the vast majority of cases, **this is not required** as Chisel can figure out how to clone most bundles automatically.
Note that in the vast majority of cases, **this is not required** as Chisel can figure out how to clone most bundles
automatically.

Here is an example of a parametrized bundle (`ExampleBundle`) that features a custom `cloneType`.
```scala
```scala mdoc:silent
class ExampleBundle(a: Int, b: Int) extends Bundle {
val foo = UInt(a.W)
val bar = UInt(b.W)
Expand Down Expand Up @@ -170,31 +183,33 @@ class Top extends Module {

Generally cloneType can be automatically defined if all arguments to the Bundle are vals e.g.

```scala
class MyBundle(val width: Int) extends Bundle {
val field = UInt(width.W)
```scala mdoc:silent
class MyCloneTypeBundle(val bitwidth: Int) extends Bundle {
val field = UInt(bitwidth.W)
// ...
}
```

The only caveat is if you are passing something of type Data as a "generator" parameter, in which case you should make it a `private val`.
The only caveat is if you are passing something of type Data as a "generator" parameter, in which case you should make
it a `private val`.

For example, consider the following Bundle:
For example, consider the following Bundle. Because its `gen` variable is not a `private val`, the user has to
explicitly define the `cloneType` method.

```scala
class RegisterWriteIO[T <: Data](gen: T) extends Bundle {
```scala mdoc:silent
import chisel3.util.{Decoupled, Irrevocable}
class RegisterWriteIOExplicitCloneType[T <: Data](gen: T) extends Bundle {
val request = Flipped(Decoupled(gen))
val response = Irrevocable(Bool()) // ignore .bits

override def cloneType = new RegisterWriteIO(gen).asInstanceOf[this.type]
val response = Irrevocable(Bool())
override def cloneType = new RegisterWriteIOExplicitCloneType(gen).asInstanceOf[this.type]
}
```

We can make this this infer cloneType by making `gen` private since it is a "type parameter":

```scala
```scala mdoc:silent
class RegisterWriteIO[T <: Data](private val gen: T) extends Bundle {
val request = Flipped(Decoupled(gen))
val response = Irrevocable(Bool()) // ignore .bits
val response = Irrevocable(Bool())
}
```