From 03e6c2ba149ac611d1e2329c4502fed0ccea48fe Mon Sep 17 00:00:00 2001 From: Adam Izraelevitz Date: Mon, 5 Oct 2020 12:29:40 -0700 Subject: Move more docs (#1601) * Fix broken mdoc * Added test-chisel-docs to ci workflow * Add requirement on build-treadle job * Added forgotton colon * Forgot cd into chisel3 dir * moved three docs into explanations * Updated reference Co-authored-by: Schuyler Eldridge --- docs/src/explanations/annotations.md | 141 ++++++++++++++++++ docs/src/explanations/blackboxes.md | 147 ++++++++++++++++++ docs/src/explanations/bundles-and-vecs.md | 215 +++++++++++++++++++++++++++ docs/src/wiki-deprecated/annotations.md | 141 ------------------ docs/src/wiki-deprecated/blackboxes.md | 131 ---------------- docs/src/wiki-deprecated/bundles-and-vecs.md | 200 ------------------------- 6 files changed, 503 insertions(+), 472 deletions(-) create mode 100644 docs/src/explanations/annotations.md create mode 100644 docs/src/explanations/blackboxes.md create mode 100644 docs/src/explanations/bundles-and-vecs.md delete mode 100644 docs/src/wiki-deprecated/annotations.md delete mode 100644 docs/src/wiki-deprecated/blackboxes.md delete mode 100644 docs/src/wiki-deprecated/bundles-and-vecs.md diff --git a/docs/src/explanations/annotations.md b/docs/src/explanations/annotations.md new file mode 100644 index 00000000..19d24605 --- /dev/null +++ b/docs/src/explanations/annotations.md @@ -0,0 +1,141 @@ +--- +layout: docs +title: "Annotations" +section: "chisel3" +--- + +`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. + +This article focuses on the approach to building a basic library that contains `Annotation`s and `Transform`s. + +### Imports +We need a few basic imports to reference the components we need. + +```scala mdoc:silent +import chisel3._ +import chisel3.experimental.{annotate, ChiselAnnotation, RunFirrtlTransform} +import chisel3.internal.InstanceId + +import firrtl._ +import firrtl.annotations.{Annotation, SingleTargetAnnotation} +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 `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: Target, info: String) extends SingleTargetAnnotation[Target] { + def duplicate(newTarget: Target) = this.copy(target = newTarget) +} +``` + +Second, define a `Transform` that consumes this `InfoAnnotation`. +This `InfoTransform` simply reads all annotations, prints any `InfoAnnotation`s it finds, and removes them. + +```scala mdoc:invisible +object Issue1228 { + /* Workaround for https://github.com/freechipsproject/firrtl/pull/1228 */ + abstract class Transform extends firrtl.Transform { + override def name: String = this.getClass.getName + } +} +import Issue1228.Transform +``` + +```scala mdoc:silent +/** A transform that reads InfoAnnotations and prints information about them */ +class InfoTransform() extends Transform with DependencyAPIMigration { + + override def prerequisites = firrtl.stage.Forms.HighForm + + override def execute(state: CircuitState): CircuitState = { + println("Starting transform 'IdentityTransform'") + + val annotationsx = state.annotations.flatMap{ + case InfoAnnotation(a: CircuitTarget, info) => + println(s" - Circuit '${a.serialize}' annotated with '$info'") + None + case InfoAnnotation(a: ModuleTarget, info) => + println(s" - Module '${a.serialize}' annotated with '$info'") + None + 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 => + Some(a) + } + + state.copy(annotations = annotationsx) + } +} +``` + +> Note: `inputForm` and `outputForm` will be deprecated in favor of a new dependency API that allows transforms to specify their dependencies more specifically than with circuit forms. +> Full backwards compatibility for `inputForm` and `outputForm` will be maintained, however. + +### Create a Chisel API/Annotator + +Now, define a Chisel API to annotate Chisel things with this `InfoAnnotation`. +This is commonly referred to as an "annotator". + +Here, define an object, `InfoAnnotator` with a method `info` that generates `InfoAnnotation`s. +This uses the `chisel3.experimental.annotate` passed an anonymous `ChiselAnnotation` object. +The need for this `ChiselAnnotation` (which is different from an actual FIRRTL `Annotation`) is that no FIRRTL circuit exists at the time the `info` method is called. +This is delaying the generation of the `InfoAnnotation` until the full circuit is available. + +This annotator also mixes in the `RunFirrtlTransform` trait (abstract in the `transformClass` method) because this annotator, whenever used, should result in the FIRRTL compiler running the custom `InfoTransform`. + +```scala mdoc:silent +object InfoAnnotator { + def info(component: InstanceId, info: String): Unit = { + annotate(new ChiselAnnotation with RunFirrtlTransform { + def toFirrtl: Annotation = InfoAnnotation(component.toTarget, info) + def transformClass = classOf[InfoTransform] + }) + } +} +``` + +> Note: there are a number of different approaches to writing an annotator. +> You could use a trait that you mix into a `Module`, an object (like is done above), or any other software approach. +> The specific choice of how you implement this is up to you! + +### Using the Chisel API + +Now, we can use the method `InfoAnnotation.info` to create annotations that associate strings with specific things in a FIRRTL circuit. +Below is a Chisel `Module`, `ModC`, where both the actual module is annotated as well as an output. + +```scala mdoc:silent +class ModC(widthC: Int) extends Module { + val io = IO(new Bundle { + val in = Input(UInt(widthC.W)) + val out = Output(UInt(widthC.W)) + }) + io.out := io.in + + InfoAnnotator.info(this, s"ModC($widthC)") + + InfoAnnotator.info(io.out, s"ModC(ignore param)") +} +``` + +### Running the Compilation + +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 +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)))) +``` diff --git a/docs/src/explanations/blackboxes.md b/docs/src/explanations/blackboxes.md new file mode 100644 index 00000000..7064c7bb --- /dev/null +++ b/docs/src/explanations/blackboxes.md @@ -0,0 +1,147 @@ +--- +layout: docs +title: "Blackboxes" +section: "chisel3" +--- +Chisel *BlackBoxes* are used to instantiate externally defined modules. This construct is useful +for hardware constructs that cannot be described in Chisel and for connecting to FPGA or other IP not defined in Chisel. + +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. +`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_`). + +### Parameterization + +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: + +```scala mdoc:silent +import chisel3._ +import chisel3.util._ +import chisel3.experimental._ // To enable experimental features + +class IBUFDS extends BlackBox(Map("DIFF_TERM" -> "TRUE", + "IOSTANDARD" -> "DEFAULT")) { + val io = IO(new Bundle { + val O = Output(Clock()) + val I = Input(Clock()) + val IB = Input(Clock()) + }) +} + +class Top extends Module { + 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 +} +``` + +In the Chisel-generated Verilog code, `IBUFDS` will be instantiated as: + +```verilog +IBUFDS #(.DIFF_TERM("TRUE"), .IOSTANDARD("DEFAULT")) ibufds ( + .IB(ibufds_IB), + .I(ibufds_I), + .O(ibufds_O) +); +``` + +### 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 in1 = Input(UInt(64.W)) + val in2 = Input(UInt(64.W)) + val out = Output(UInt(64.W)) + }) +} +``` + +The implementation is described by the following verilog +```verilog +module BlackBoxRealAdd( + input [63:0] in1, + input [63:0] in2, + output reg [63:0] out +); + always @* begin + 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.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() { + val in1 = Input(UInt(64.W)) + val in2 = Input(UInt(64.W)) + val out = Output(UInt(64.W)) + }) + 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 +``` +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. +```scala mdoc:silent:reset +import chisel3._ +import chisel3.util.HasBlackBoxInline +class BlackBoxRealAdd extends BlackBox with HasBlackBoxInline { + val io = IO(new Bundle() { + val in1 = Input(UInt(64.W)) + val in2 = Input(UInt(64.W)) + val out = Output(UInt(64.W)) + }) + setInline("BlackBoxRealAdd.v", + """module BlackBoxRealAdd( + | input [15:0] in1, + | input [15:0] in2, + | output [15:0] out + |); + |always @* begin + | out <= $realtobits($bitstoreal(in1) + $bitstoreal(in2)); + |end + |endmodule + """.stripMargin) +} +``` +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. + +### The interpreter + +***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. diff --git a/docs/src/explanations/bundles-and-vecs.md b/docs/src/explanations/bundles-and-vecs.md new file mode 100644 index 00000000..4b1eb196 --- /dev/null +++ b/docs/src/explanations/bundles-and-vecs.md @@ -0,0 +1,215 @@ +--- +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 { + val sign = Bool() + val exponent = UInt(8.W) + val significand = UInt(23.W) +} + +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 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 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) +} +``` + +(Note that we specify the number followed by the type of the `Vec` elements. We also specifiy the width of the `SInt`) + +The set of primitive classes +(`SInt`, `UInt`, and `Bool`) plus the aggregate +classes (`Bundles` and `Vec`s) all inherit from a common +superclass, `Data`. Every object that ultimately inherits from +`Data` can be represented as a bit vector in a hardware design. + +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. + val myVec = Vec(5, SInt(23.W)) + val flag = Bool() + // Previously defined bundle. + val f = new MyFloat +} +``` + +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.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 mdoc:silent +class ABBundle extends Bundle { + val a = Input(Bool()) + val b = Output(Bool()) +} +class MyFlippedModule extends RawModule { + // Normal instantiation of the bundle + // 'a' is an Input and 'b' is an Output + 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 ABBundle)) + flippedBundle.a := flippedBundle.b +} +``` + +This generates the following Verilog: + +```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: + +```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)) + val vec = Output(MixedVec(UInt(3.W), UInt(10.W))) + }) + io.vec(0) := io.x + io.vec(1) := io.y +} +``` + +We can also programmatically create the types in a MixedVec: + +```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) })) + // ... + }) + // ...rest of the module goes here... +} +``` + +### A note on `cloneType` + +Since Chisel is built on top of Scala and the JVM, it needs to know how to construct copies of bundles for various +purposes (creating wires, IOs, etc). If you have a parametrized bundle and Chisel can't automatically figure out how to +clone your bundle, you will need to create a custom `cloneType` method in your bundle. Most of the time, this is as +simple as `override def cloneType = (new YourBundleHere(...)).asInstanceOf[this.type]`. + +Note that in the vast majority of cases, **this is not required** as Chisel can figure out how to clone most bundles +automatically. + +Here is an example of a parametrized bundle (`ExampleBundle`) that features a custom `cloneType`. +```scala mdoc:silent +class ExampleBundle(a: Int, b: Int) extends Bundle { + val foo = UInt(a.W) + val bar = UInt(b.W) + override def cloneType = (new ExampleBundle(a, b)).asInstanceOf[this.type] +} + +class ExampleBundleModule(btype: ExampleBundle) extends Module { + val io = IO(new Bundle { + val out = Output(UInt(32.W)) + val b = Input(chiselTypeOf(btype)) + }) + io.out := io.b.foo + io.b.bar +} + +class Top extends Module { + val io = IO(new Bundle { + val out = Output(UInt(32.W)) + val in = Input(UInt(17.W)) + }) + val x = Wire(new ExampleBundle(31, 17)) + x := DontCare + val m = Module(new ExampleBundleModule(x)) + m.io.b.foo := io.in + m.io.b.bar := io.in + io.out := m.io.out +} +``` + +Generally cloneType can be automatically defined if all arguments to the Bundle are vals e.g. + +```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`. + +For example, consider the following Bundle. Because its `gen` variable is not a `private val`, the user has to +explicitly define the `cloneType` method. + +```scala mdoc:silent +import chisel3.util.{Decoupled, Irrevocable} +class RegisterWriteIOExplicitCloneType[T <: Data](gen: T) extends Bundle { + val request = Flipped(Decoupled(gen)) + 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 mdoc:silent +class RegisterWriteIO[T <: Data](private val gen: T) extends Bundle { + val request = Flipped(Decoupled(gen)) + val response = Irrevocable(Bool()) +} +``` diff --git a/docs/src/wiki-deprecated/annotations.md b/docs/src/wiki-deprecated/annotations.md deleted file mode 100644 index 4b55d44d..00000000 --- a/docs/src/wiki-deprecated/annotations.md +++ /dev/null @@ -1,141 +0,0 @@ ---- -layout: docs -title: "Annotations" -section: "chisel3" ---- - -`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. - -This article focuses on the approach to building a basic library that contains `Annotation`s and `Transform`s. - -### Imports -We need a few basic imports to reference the components we need. - -```scala mdoc:silent -import chisel3._ -import chisel3.experimental.{annotate, ChiselAnnotation, RunFirrtlTransform} -import chisel3.internal.InstanceId - -import firrtl._ -import firrtl.annotations.{Annotation, SingleTargetAnnotation} -import firrtl.annotations.{CircuitName, ComponentName, ModuleName, Named} -``` - -### Define an `Annotation` and a `Transform` - -First, define an `Annotation` that contains a string associated with a `Named` 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) -} -``` - -> 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. - -```scala mdoc:invisible -object Issue1228 { - /* Workaround for https://github.com/freechipsproject/firrtl/pull/1228 */ - abstract class Transform extends firrtl.Transform { - override def name: String = this.getClass.getName - } -} -import Issue1228.Transform -``` - -```scala mdoc:silent -/** A transform that reads InfoAnnotations and prints information about them */ -class InfoTransform() extends Transform with DependencyAPIMigration { - - override def prerequisites = firrtl.stage.Forms.HighForm - - override def execute(state: CircuitState): CircuitState = { - println("Starting transform 'IdentityTransform'") - - val annotationsx = state.annotations.flatMap{ - case InfoAnnotation(a: CircuitName, info) => - println(s" - Circuit '${a.serialize}' annotated with '$info'") - None - case InfoAnnotation(a: ModuleName, info) => - println(s" - Module '${a.serialize}' annotated with '$info'") - None - case InfoAnnotation(a: ComponentName, info) => - println(s" - Component '${a.serialize} annotated with '$info''") - None - case a => - Some(a) - } - - state.copy(annotations = annotationsx) - } -} -``` - -> Note: `inputForm` and `outputForm` will be deprecated in favor of a new dependency API that allows transforms to specify their dependencies more specifically than with circuit forms. -> Full backwards compatibility for `inputForm` and `outputForm` will be maintained, however. - -### Create a Chisel API/Annotator - -Now, define a Chisel API to annotate Chisel things with this `InfoAnnotation`. -This is commonly referred to as an "annotator". - -Here, define an object, `InfoAnnotator` with a method `info` that generates `InfoAnnotation`s. -This uses the `chisel3.experimental.annotate` passed an anonymous `ChiselAnnotation` object. -The need for this `ChiselAnnotation` (which is different from an actual FIRRTL `Annotation`) is that no FIRRTL circuit exists at the time the `info` method is called. -This is delaying the generation of the `InfoAnnotation` until the full circuit is available. - -This annotator also mixes in the `RunFirrtlTransform` trait (abstract in the `transformClass` method) because this annotator, whenever used, should result in the FIRRTL compiler running the custom `InfoTransform`. - -```scala mdoc:silent -object InfoAnnotator { - def info(component: InstanceId, info: String): Unit = { - annotate(new ChiselAnnotation with RunFirrtlTransform { - def toFirrtl: Annotation = InfoAnnotation(component.toNamed, info) - def transformClass = classOf[InfoTransform] - }) - } -} -``` - -> Note: there are a number of different approaches to writing an annotator. -> You could use a trait that you mix into a `Module`, an object (like is done above), or any other software approach. -> The specific choice of how you implement this is up to you! - -### Using the Chisel API - -Now, we can use the method `InfoAnnotation.info` to create annotations that associate strings with specific things in a FIRRTL circuit. -Below is a Chisel `Module`, `ModC`, where both the actual module is annotated as well as an output. - -```scala mdoc:silent -class ModC(widthC: Int) extends Module { - val io = IO(new Bundle { - val in = Input(UInt(widthC.W)) - val out = Output(UInt(widthC.W)) - }) - io.out := io.in - - InfoAnnotator.info(this, s"ModC($widthC)") - - InfoAnnotator.info(io.out, s"ModC(ignore param)") -} -``` - -### Running the Compilation - -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 -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)))) -``` diff --git a/docs/src/wiki-deprecated/blackboxes.md b/docs/src/wiki-deprecated/blackboxes.md deleted file mode 100644 index 686c9719..00000000 --- a/docs/src/wiki-deprecated/blackboxes.md +++ /dev/null @@ -1,131 +0,0 @@ ---- -layout: docs -title: "Blackboxes" -section: "chisel3" ---- -Chisel *BlackBoxes* are used to instantiate externally defined modules. This construct is useful -for hardware constructs that cannot be described in Chisel and for connecting to FPGA or other IP not defined in Chisel. - -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. -`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_`). - -### 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: - -```scala mdoc:silent -import chisel3._ -import chisel3.util._ -import chisel3.experimental._ // To enable experimental features - -class IBUFDS extends BlackBox(Map("DIFF_TERM" -> "TRUE", - "IOSTANDARD" -> "DEFAULT")) { - val io = IO(new Bundle { - val O = Output(Clock()) - val I = Input(Clock()) - val IB = Input(Clock()) - }) -} - -class Top extends Module { - 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 -} -``` - -In the Chisel-generated Verilog code, `IBUFDS` will be instantiated as: - -```verilog -IBUFDS #(.DIFF_TERM("TRUE"), .IOSTANDARD("DEFAULT")) ibufds ( - .IB(ibufds_IB), - .I(ibufds_I), - .O(ibufds_O) -); -``` - -### 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 in1 = Input(UInt(64.W)) - val in2 = Input(UInt(64.W)) - val out = Output(UInt(64.W)) - }) -} -``` - -The implementation is described by the following verilog -```verilog -module BlackBoxRealAdd( - input [63:0] in1, - input [63:0] in2, - output reg [63:0] out -); - always @* begin - 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](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() { - val in1 = Input(UInt(64.W)) - val in2 = Input(UInt(64.W)) - val out = Output(UInt(64.W)) - }) - 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 -``` -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. -```scala mdoc:silent:reset -import chisel3._ -import chisel3.util.HasBlackBoxInline -class BlackBoxRealAdd extends BlackBox with HasBlackBoxInline { - val io = IO(new Bundle() { - val in1 = Input(UInt(64.W)) - val in2 = Input(UInt(64.W)) - val out = Output(UInt(64.W)) - }) - setInline("BlackBoxRealAdd.v", - """module BlackBoxRealAdd( - | input [15:0] in1, - | input [15:0] in2, - | output [15:0] out - |); - |always @* begin - | out <= $realtobits($bitstoreal(in1) + $bitstoreal(in2)); - |end - |endmodule - """.stripMargin) -} -``` -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. - -### 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. diff --git a/docs/src/wiki-deprecated/bundles-and-vecs.md b/docs/src/wiki-deprecated/bundles-and-vecs.md deleted file mode 100644 index 0a0e2a43..00000000 --- a/docs/src/wiki-deprecated/bundles-and-vecs.md +++ /dev/null @@ -1,200 +0,0 @@ ---- -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 -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 -``` - -> 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 -``` - -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))) - -// 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`) - -The set of primitive classes -(`SInt`, `UInt`, and `Bool`) plus the aggregate -classes (`Bundles` and `Vec`s) all inherit from a common -superclass, `Data`. Every object that ultimately inherits from -`Data` can be represented as a bit vector in a hardware design. - -Bundles and Vecs can be arbitrarily nested to build complex data -structures: -```scala -class BigBundle extends Bundle { - // Vector of 5 23-bit signed integers. - val myVec = Vec(5, SInt(23.W)) - val flag = Bool() - // Previously defined bundle. - val f = new MyFloat -} -``` - -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). - -### 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 { - val a = Input(Bool()) - val b = Output(Bool()) -} -class MyModule extends RawModule { - // Normal instantiation of the bundle - // 'a' is an Input and 'b' is an Output - val normalBundle = IO(new MyBundle) - 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)) - 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 -``` - -### 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: - -```scala -class MyModule extends Module { - val io = IO(new Bundle { - val x = Input(UInt(3.W)) - val y = Input(UInt(10.W)) - val vec = Output(MixedVec(UInt(3.W), UInt(10.W))) - }) - io.vec(0) := io.x - io.vec(1) := io.y -} -``` - -We can also programmatically create the types in a MixedVec: - -```scala -class MyModule(x: Int, y: Int) extends Module { - val io = IO(new Bundle { - val vec = Input(MixedVec((x to y) map { i => UInt(i.W) })) - // ... - }) - // ...rest of the module goes here... -} -``` - -### A note on `cloneType` - -Since Chisel is built on top of Scala and the JVM, it needs to know how to construct copies of bundles for various purposes (creating wires, IOs, etc). If you have a parametrized bundle and Chisel can't automatically figure out how to clone your bundle, you will need to create a custom `cloneType` method in your bundle. Most of the time, this is as simple as `override def cloneType = (new YourBundleHere(...)).asInstanceOf[this.type]`. - -Note that in the vast majority of cases, **this is not required** as Chisel can figure out how to clone most bundles automatically. - -Here is an example of a parametrized bundle (`ExampleBundle`) that features a custom `cloneType`. -```scala -class ExampleBundle(a: Int, b: Int) extends Bundle { - val foo = UInt(a.W) - val bar = UInt(b.W) - override def cloneType = (new ExampleBundle(a, b)).asInstanceOf[this.type] -} - -class ExampleBundleModule(btype: ExampleBundle) extends Module { - val io = IO(new Bundle { - val out = Output(UInt(32.W)) - val b = Input(chiselTypeOf(btype)) - }) - io.out := io.b.foo + io.b.bar -} - -class Top extends Module { - val io = IO(new Bundle { - val out = Output(UInt(32.W)) - val in = Input(UInt(17.W)) - }) - val x = Wire(new ExampleBundle(31, 17)) - x := DontCare - val m = Module(new ExampleBundleModule(x)) - m.io.b.foo := io.in - m.io.b.bar := io.in - io.out := m.io.out -} -``` - -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) - // ... -} -``` - -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: - -```scala -class RegisterWriteIO[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] -} -``` - -We can make this this infer cloneType by making `gen` private since it is a "type parameter": - -```scala -class RegisterWriteIO[T <: Data](private val gen: T) extends Bundle { - val request = Flipped(Decoupled(gen)) - val response = Irrevocable(Bool()) // ignore .bits -} -``` -- cgit v1.2.3