From 5b7b612b8b79e5b7e3e8b37afbcc19646a090061 Mon Sep 17 00:00:00 2001 From: Adam Izraelevitz Date: Thu, 20 Aug 2020 15:23:05 -0700 Subject: [PATCH 1/4] Added website docs and mdoc. Removed all warnings --- .gitignore | 3 + build.sbt | 15 + docs/README.md | 23 + docs/src/annotations.md | 141 ++++++ docs/src/blackboxes.md | 131 +++++ docs/src/bundles-and-vecs.md | 200 ++++++++ docs/src/chisel3-vs-chisel2.md | 203 ++++++++ docs/src/combinational-circuits.md | 81 +++ docs/src/cookbook.md | 470 ++++++++++++++++++ docs/src/data-types.md | 134 +++++ docs/src/developers.md | 11 + docs/src/experimental-features.md | 119 +++++ docs/src/faqs.md | 246 +++++++++ docs/src/functional-abstraction.md | 29 ++ docs/src/functional-module-creation.md | 79 +++ {doc => docs/src}/images/Makefile | 0 {doc => docs/src}/images/chisel_logo.png | Bin {doc => docs/src}/images/chisel_logo.svg | 0 {doc => docs/src}/images/fir_filter.svg | 0 {doc => docs/src}/images/type_hierarchy.dot | 0 {doc => docs/src}/images/type_hierarchy.png | Bin {doc => docs/src}/images/type_hierarchy.svg | 0 {doc => docs/src}/images/vec-forall.svg | 0 docs/src/index.md | 10 + docs/src/interfaces-and-connections.md | 144 ++++++ docs/src/interval-type.md | 55 ++ docs/src/introduction.md | 64 +++ docs/src/memories.md | 170 +++++++ docs/src/modules.md | 141 ++++++ docs/src/multi-clock.md | 81 +++ docs/src/muxes-and-input-selection.md | 56 +++ docs/src/operators.md | 63 +++ docs/src/polymorphism-and-parameterization.md | 209 ++++++++ docs/src/ports.md | 68 +++ docs/src/printing.md | 130 +++++ docs/src/reset.md | 177 +++++++ docs/src/resources.md | 14 + docs/src/sbt-subproject.md | 36 ++ docs/src/sequential-circuits.md | 42 ++ {doc => docs/src}/style.md | 0 docs/src/supported-hardware.md | 8 + docs/src/test-coverage.md | 21 + docs/src/troubleshooting.md | 57 +++ docs/src/unconnected-wires.md | 112 +++++ docs/src/upgrading-from-scala-2-11.md | 86 ++++ docs/src/width-inference.md | 37 ++ project/plugins.sbt | 2 + 47 files changed, 3668 insertions(+) create mode 100644 docs/README.md create mode 100644 docs/src/annotations.md create mode 100644 docs/src/blackboxes.md create mode 100644 docs/src/bundles-and-vecs.md create mode 100644 docs/src/chisel3-vs-chisel2.md create mode 100644 docs/src/combinational-circuits.md create mode 100644 docs/src/cookbook.md create mode 100644 docs/src/data-types.md create mode 100644 docs/src/developers.md create mode 100644 docs/src/experimental-features.md create mode 100644 docs/src/faqs.md create mode 100644 docs/src/functional-abstraction.md create mode 100644 docs/src/functional-module-creation.md rename {doc => docs/src}/images/Makefile (100%) rename {doc => docs/src}/images/chisel_logo.png (100%) rename {doc => docs/src}/images/chisel_logo.svg (100%) rename {doc => docs/src}/images/fir_filter.svg (100%) rename {doc => docs/src}/images/type_hierarchy.dot (100%) rename {doc => docs/src}/images/type_hierarchy.png (100%) rename {doc => docs/src}/images/type_hierarchy.svg (100%) rename {doc => docs/src}/images/vec-forall.svg (100%) create mode 100644 docs/src/index.md create mode 100644 docs/src/interfaces-and-connections.md create mode 100644 docs/src/interval-type.md create mode 100644 docs/src/introduction.md create mode 100644 docs/src/memories.md create mode 100644 docs/src/modules.md create mode 100644 docs/src/multi-clock.md create mode 100644 docs/src/muxes-and-input-selection.md create mode 100644 docs/src/operators.md create mode 100644 docs/src/polymorphism-and-parameterization.md create mode 100644 docs/src/ports.md create mode 100644 docs/src/printing.md create mode 100644 docs/src/reset.md create mode 100644 docs/src/resources.md create mode 100644 docs/src/sbt-subproject.md create mode 100644 docs/src/sequential-circuits.md rename {doc => docs/src}/style.md (100%) create mode 100644 docs/src/supported-hardware.md create mode 100644 docs/src/test-coverage.md create mode 100644 docs/src/troubleshooting.md create mode 100644 docs/src/unconnected-wires.md create mode 100644 docs/src/upgrading-from-scala-2-11.md create mode 100644 docs/src/width-inference.md diff --git a/.gitignore b/.gitignore index 12a8e6f99e9..5e7271513a3 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,9 @@ generated/ target/ *.iml *.swp +*.fir +*.v +*.json test_run_dir *~ \#*\# diff --git a/build.sbt b/build.sbt index 60ded7294f4..0b0afb4aa3b 100644 --- a/build.sbt +++ b/build.sbt @@ -239,6 +239,21 @@ lazy val chisel = (project in file(".")). ) ) +lazy val docs = project // new documentation project + .in(file("docs-target")) // important: it must not be docs/ + .dependsOn(chisel) + .enablePlugins(MdocPlugin) + .settings(commonSettings) + .settings( + scalacOptions += "-language:reflectiveCalls", + mdocIn := file("docs/src"), + mdocOut := file("docs/generated"), + mdocExtraArguments := Seq("--cwd", "docs"), + mdocVariables := Map( + "BUILD_DIR" -> "docs-target" // build dir for mdoc programs to dump temp files + ) + ) + addCommandAlias("com", "all compile") addCommandAlias("lint", "; compile:scalafix --check ; test:scalafix --check") addCommandAlias("fix", "all compile:scalafix test:scalafix") diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000000..2b7e293de97 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,23 @@ +# chisel3/docs/README.md + +This directory contains documentation on the code within this repository. +Documents can either be written directly in markdown, or +use embedded [mdoc](https://scalameta.org/mdoc/) +which compiles against the `chisel3` (and dependencies) codebase +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. + +For each topic, we categorize documentation as described in +[Divio's documentation system](https://documentation.divio.com/). + +These directories contain 3 documentation types: +* Tutorials +* Explanation +* How-To Guides + +Note that the 4th documentation type, "Reference", is omitted here. +We are working on generating API documentation from the code. + +## Topic Table of Contents: + diff --git a/docs/src/annotations.md b/docs/src/annotations.md new file mode 100644 index 00000000000..4b55d44dfea --- /dev/null +++ b/docs/src/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.{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/blackboxes.md b/docs/src/blackboxes.md new file mode 100644 index 00000000000..686c9719bca --- /dev/null +++ b/docs/src/blackboxes.md @@ -0,0 +1,131 @@ +--- +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/bundles-and-vecs.md b/docs/src/bundles-and-vecs.md new file mode 100644 index 00000000000..0a0e2a43ede --- /dev/null +++ b/docs/src/bundles-and-vecs.md @@ -0,0 +1,200 @@ +--- +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 +} +``` diff --git a/docs/src/chisel3-vs-chisel2.md b/docs/src/chisel3-vs-chisel2.md new file mode 100644 index 00000000000..6f14a2ebb27 --- /dev/null +++ b/docs/src/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](bundles-and-vecs.md)) 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/combinational-circuits.md b/docs/src/combinational-circuits.md new file mode 100644 index 00000000000..813549c91d3 --- /dev/null +++ b/docs/src/combinational-circuits.md @@ -0,0 +1,81 @@ +--- +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/cookbook.md b/docs/src/cookbook.md new file mode 100644 index 00000000000..985816472b4 --- /dev/null +++ b/docs/src/cookbook.md @@ -0,0 +1,470 @@ +--- +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.md#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._ +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 for a `MultiIOModule` where an entire `IO` is optional: + +```scala mdoc:silent:reset +import chisel3._ + +class ModuleWithOptionalIO(flag: Boolean) extends MultiIOModule { + 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/data-types.md b/docs/src/data-types.md new file mode 100644 index 00000000000..227dee66a2f --- /dev/null +++ b/docs/src/data-types.md @@ -0,0 +1,134 @@ +--- +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.md) + +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/developers.md b/docs/src/developers.md new file mode 100644 index 00000000000..ba5a1a62492 --- /dev/null +++ b/docs/src/developers.md @@ -0,0 +1,11 @@ +--- +layout: docs +title: "Developers" +section: "chisel3" +--- +# Developer Documentation + +Tips and tricks for Chisel developers. + +* [Embedding Chisel as an sbt subproject](sbt-subproject.md) +* [Test Coverage](test-coverage.md) diff --git a/docs/src/experimental-features.md b/docs/src/experimental-features.md new file mode 100644 index 00000000000..d36b2946aa7 --- /dev/null +++ b/docs/src/experimental-features.md @@ -0,0 +1,119 @@ +--- +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/faqs.md b/docs/src/faqs.md new file mode 100644 index 00000000000..dfb01afeaf1 --- /dev/null +++ b/docs/src/faqs.md @@ -0,0 +1,246 @@ +--- +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.md). + +### 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.md) + +>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.md) 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.md) 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/functional-abstraction.md b/docs/src/functional-abstraction.md new file mode 100644 index 00000000000..04dde7d18db --- /dev/null +++ b/docs/src/functional-abstraction.md @@ -0,0 +1,29 @@ +--- +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/functional-module-creation.md b/docs/src/functional-module-creation.md new file mode 100644 index 00000000000..3e2e95bc5e8 --- /dev/null +++ b/docs/src/functional-module-creation.md @@ -0,0 +1,79 @@ +--- +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/doc/images/Makefile b/docs/src/images/Makefile similarity index 100% rename from doc/images/Makefile rename to docs/src/images/Makefile diff --git a/doc/images/chisel_logo.png b/docs/src/images/chisel_logo.png similarity index 100% rename from doc/images/chisel_logo.png rename to docs/src/images/chisel_logo.png diff --git a/doc/images/chisel_logo.svg b/docs/src/images/chisel_logo.svg similarity index 100% rename from doc/images/chisel_logo.svg rename to docs/src/images/chisel_logo.svg diff --git a/doc/images/fir_filter.svg b/docs/src/images/fir_filter.svg similarity index 100% rename from doc/images/fir_filter.svg rename to docs/src/images/fir_filter.svg diff --git a/doc/images/type_hierarchy.dot b/docs/src/images/type_hierarchy.dot similarity index 100% rename from doc/images/type_hierarchy.dot rename to docs/src/images/type_hierarchy.dot diff --git a/doc/images/type_hierarchy.png b/docs/src/images/type_hierarchy.png similarity index 100% rename from doc/images/type_hierarchy.png rename to docs/src/images/type_hierarchy.png diff --git a/doc/images/type_hierarchy.svg b/docs/src/images/type_hierarchy.svg similarity index 100% rename from doc/images/type_hierarchy.svg rename to docs/src/images/type_hierarchy.svg diff --git a/doc/images/vec-forall.svg b/docs/src/images/vec-forall.svg similarity index 100% rename from doc/images/vec-forall.svg rename to docs/src/images/vec-forall.svg diff --git a/docs/src/index.md b/docs/src/index.md new file mode 100644 index 00000000000..9401fce8342 --- /dev/null +++ b/docs/src/index.md @@ -0,0 +1,10 @@ +--- +layout: docs +title: "Chisel3" +section: "chisel3" +position: 1 +--- + +This is a brief overview to the Chisel HDL. + +If this is your first time with Chisel or Scala the [**online Chisel Bootcamp**](https://mybinder.org/v2/gh/freechipsproject/chisel-bootcamp/master) is the recommended way to get started. diff --git a/docs/src/interfaces-and-connections.md b/docs/src/interfaces-and-connections.md new file mode 100644 index 00000000000..5902f5cdae7 --- /dev/null +++ b/docs/src/interfaces-and-connections.md @@ -0,0 +1,144 @@ +--- +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/interval-type.md b/docs/src/interval-type.md new file mode 100644 index 00000000000..7f33461e16f --- /dev/null +++ b/docs/src/interval-type.md @@ -0,0 +1,55 @@ +# 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/introduction.md b/docs/src/introduction.md new file mode 100644 index 00000000000..43fc9887388 --- /dev/null +++ b/docs/src/introduction.md @@ -0,0 +1,64 @@ +--- +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/memories.md b/docs/src/memories.md new file mode 100644 index 00000000000..6104309c55b --- /dev/null +++ b/docs/src/memories.md @@ -0,0 +1,170 @@ +--- +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.md) 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/modules.md b/docs/src/modules.md new file mode 100644 index 00000000000..1d85b88e6ae --- /dev/null +++ b/docs/src/modules.md @@ -0,0 +1,141 @@ +--- +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 an interface wrapped in a Module's ```IO()``` method and 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`). For different behavior, Chisel +provides both `MultiIOModule` and `RawModule`. + +### `MultiIOModule` + +A `MultiIOModule` allows you to define as many different `IO` as needed +and does not require you to implement an abstract member `io`. +This can be useful when programmatically adding `IO` or adding `IO` via inheritance. +An artifact of this is that Verilog generated from a `MultiIOModule` will +*not* have the `io_` prefix. `MultiIOModule`s still have an implicit +clock and reset like `Module`. + + + +### `RawModule` + +A `RawModule` is a module that allows you to define as much `IO` as needed +(like `MultiIOModule`) but **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/multi-clock.md b/docs/src/multi-clock.md new file mode 100644 index 00000000000..528ba8a46c5 --- /dev/null +++ b/docs/src/multi-clock.md @@ -0,0 +1,81 @@ +--- +layout: docs +title: "Multiple Clock Domains" +section: "chisel3" +--- +Chisel 3 supports multiple clock domains as follows. + +Note that in order to cross clock domains safely, you will need appropriate synchronization logic (such as an asynchronous FIFO). You can use the [AsyncQueue library](https://github.com/ucb-bar/asyncqueue) to do this easily. + +```scala +class MultiClockModule extends Module { + val io = IO(new Bundle { + val clockB = Input(Clock()) + val resetB = Input(Bool()) + val stuff = Input(Bool()) + }) + + // This register is clocked against the module clock. + val regClock = RegNext(io.stuff) + + withClockAndReset (io.clockB, io.resetB) { + // In this withClock scope, all synchronous elements are clocked against io.clockB. + // Reset for flops in this domain is using the explicitly provided reset io.resetB. + + // This register is clocked against io.clockB. + val regClockB = RegNext(io.stuff) + } + + // This register is also clocked against the module clock. + val regClock2 = RegNext(io.stuff) +} +``` + +You can also instantiate modules in another clock domain: + +```scala +class MultiClockModule extends Module { + val io = IO(new Bundle { + val clockB = Input(Clock()) + val resetB = Input(Bool()) + val stuff = Input(Bool()) + }) + val clockB_child = withClockAndReset(io.clockB, io.resetB) { Module(new ChildModule) } + clockB_child.io.in := io.stuff +} +``` + +If you only want to connect your clock to a new clock domain and use the regular implicit reset signal, you can use `withClock(clock)` instead of `withClockAndReset`. + +```scala +class MultiClockModule extends Module { + val io = IO(new Bundle { + val clockB = Input(Clock()) + val stuff = Input(Bool()) + }) + + // This register is clocked against the module clock. + val regClock = RegNext(io.stuff) + + withClock (io.clockB) { + // In this withClock scope, all synchronous elements are clocked against io.clockB. + + // This register is clocked against io.clockB, but uses implict reset from the parent context. + val regClockB = RegNext(io.stuff) + } + + // This register is also clocked against the module clock. + val regClock2 = RegNext(io.stuff) +} + +// Instantiate module in another clock domain with implicit reset. +class MultiClockModule extends Module { + val io = IO(new Bundle { + val clockB = Input(Clock()) + val stuff = Input(Bool()) + }) + val clockB_child = withClock(io.clockB) { Module(new ChildModule) } + clockB_child.io.in := io.stuff +} + +``` diff --git a/docs/src/muxes-and-input-selection.md b/docs/src/muxes-and-input-selection.md new file mode 100644 index 00000000000..fd7b7e7f52c --- /dev/null +++ b/docs/src/muxes-and-input-selection.md @@ -0,0 +1,56 @@ +--- +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/operators.md b/docs/src/operators.md new file mode 100644 index 00000000000..c23e2009956 --- /dev/null +++ b/docs/src/operators.md @@ -0,0 +1,63 @@ +--- +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/polymorphism-and-parameterization.md b/docs/src/polymorphism-and-parameterization.md new file mode 100644 index 00000000000..c652baca4b3 --- /dev/null +++ b/docs/src/polymorphism-and-parameterization.md @@ -0,0 +1,209 @@ +--- +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/ports.md b/docs/src/ports.md new file mode 100644 index 00000000000..f8c30b7a308 --- /dev/null +++ b/docs/src/ports.md @@ -0,0 +1,68 @@ +--- +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+ introduces an API `DataMirror.modulePorts` which can be used to inspect the IOs of any Chisel module, including MultiIOModules, RawModules, and BlackBoxes. + +Here is an example of how to use this API: + +```scala +import chisel3.experimental.DataMirror + +class Adder extends MultiIOModule { + 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 MultiIOModule { + 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/printing.md b/docs/src/printing.md new file mode 100644 index 00000000000..36dcfaae997 --- /dev/null +++ b/docs/src/printing.md @@ -0,0 +1,130 @@ +--- +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/reset.md b/docs/src/reset.md new file mode 100644 index 00000000000..5f9626dd7f1 --- /dev/null +++ b/docs/src/reset.md @@ -0,0 +1,177 @@ +--- +layout: docs +title: "Reset" +section: "chisel3" +--- + +```scala mdoc:invisible +import chisel3._ + +class Submodule extends MultiIOModule +``` + +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 MultiIOModule with RequireSyncReset { + val mySyncResetReg = RegInit(false.B) // reset is of type Bool +} +``` + +```scala mdoc:silent +class MyAlwaysAsyncResetModule extends MultiIOModule 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"](multi-clock.md) for more information about `withReset`. + + +The following will make `myReg` as well as both `resetAgnosticReg`s synchronously reset: + +```scala mdoc:silent +class ForcedSyncReset extends MultiIOModule { + // 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 MultiIOModule { + // 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 MultiIOModule { + 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/resources.md b/docs/src/resources.md new file mode 100644 index 00000000000..8b75be49bf3 --- /dev/null +++ b/docs/src/resources.md @@ -0,0 +1,14 @@ +--- +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/sbt-subproject.md b/docs/src/sbt-subproject.md new file mode 100644 index 00000000000..77273800239 --- /dev/null +++ b/docs/src/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/sequential-circuits.md b/docs/src/sequential-circuits.md new file mode 100644 index 00000000000..10294403cbe --- /dev/null +++ b/docs/src/sequential-circuits.md @@ -0,0 +1,42 @@ +--- +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/doc/style.md b/docs/src/style.md similarity index 100% rename from doc/style.md rename to docs/src/style.md diff --git a/docs/src/supported-hardware.md b/docs/src/supported-hardware.md new file mode 100644 index 00000000000..9dad221d32d --- /dev/null +++ b/docs/src/supported-hardware.md @@ -0,0 +1,8 @@ +--- +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.md). + +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/test-coverage.md b/docs/src/test-coverage.md new file mode 100644 index 00000000000..a3a622a2897 --- /dev/null +++ b/docs/src/test-coverage.md @@ -0,0 +1,21 @@ +--- +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/troubleshooting.md b/docs/src/troubleshooting.md new file mode 100644 index 00000000000..333adec41cb --- /dev/null +++ b/docs/src/troubleshooting.md @@ -0,0 +1,57 @@ +--- +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/unconnected-wires.md b/docs/src/unconnected-wires.md new file mode 100644 index 00000000000..1fa12e596a2 --- /dev/null +++ b/docs/src/unconnected-wires.md @@ -0,0 +1,112 @@ +--- +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/upgrading-from-scala-2-11.md b/docs/src/upgrading-from-scala-2-11.md new file mode 100644 index 00000000000..89d89566b12 --- /dev/null +++ b/docs/src/upgrading-from-scala-2-11.md @@ -0,0 +1,86 @@ +--- +layout: docs +title: "Upgrading From Scala 2.11" +section: "chisel3" +--- + + +```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/width-inference.md b/docs/src/width-inference.md new file mode 100644 index 00000000000..60f9d519d0f --- /dev/null +++ b/docs/src/width-inference.md @@ -0,0 +1,37 @@ +--- +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. diff --git a/project/plugins.sbt b/project/plugins.sbt index 48c2fba3254..24ee55eb3f3 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -15,3 +15,5 @@ addSbtPlugin("com.eed3si9n" % "sbt-unidoc" % "0.4.3") addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.9.15") addSbtPlugin("com.thoughtworks.sbt-api-mappings" % "sbt-api-mappings" % "3.0.0") + +addSbtPlugin("org.scalameta" % "sbt-mdoc" % "2.2.5" ) From 384c6d282dac38086841c94484db0b1a45afdfed Mon Sep 17 00:00:00 2001 From: Adam Izraelevitz Date: Fri, 21 Aug 2020 10:42:04 -0700 Subject: [PATCH 2/4] Updated README and added build to circle ci --- .circleci/config.yml | 11 +++++++++ README.md | 4 ++-- docs/README.md | 23 +++++++++++-------- docs/src/{ => wiki}/annotations.md | 0 docs/src/{ => wiki}/blackboxes.md | 0 docs/src/{ => wiki}/bundles-and-vecs.md | 0 docs/src/{ => wiki}/chisel3-vs-chisel2.md | 0 docs/src/{ => wiki}/combinational-circuits.md | 0 docs/src/{ => wiki}/cookbook.md | 0 docs/src/{ => wiki}/data-types.md | 0 docs/src/{ => wiki}/developers.md | 0 docs/src/{ => wiki}/experimental-features.md | 0 docs/src/{ => wiki}/faqs.md | 0 docs/src/{ => wiki}/functional-abstraction.md | 0 .../{ => wiki}/functional-module-creation.md | 0 docs/src/{ => wiki}/index.md | 0 .../{ => wiki}/interfaces-and-connections.md | 0 docs/src/{ => wiki}/interval-type.md | 0 docs/src/{ => wiki}/introduction.md | 0 docs/src/{ => wiki}/memories.md | 0 docs/src/{ => wiki}/modules.md | 0 docs/src/{ => wiki}/multi-clock.md | 0 .../{ => wiki}/muxes-and-input-selection.md | 0 docs/src/{ => wiki}/operators.md | 0 .../polymorphism-and-parameterization.md | 0 docs/src/{ => wiki}/ports.md | 0 docs/src/{ => wiki}/printing.md | 0 docs/src/{ => wiki}/reset.md | 0 docs/src/{ => wiki}/resources.md | 0 docs/src/{ => wiki}/sbt-subproject.md | 0 docs/src/{ => wiki}/sequential-circuits.md | 0 docs/src/{ => wiki}/style.md | 0 docs/src/{ => wiki}/supported-hardware.md | 0 docs/src/{ => wiki}/test-coverage.md | 0 docs/src/{ => wiki}/troubleshooting.md | 0 docs/src/{ => wiki}/unconnected-wires.md | 0 .../{ => wiki}/upgrading-from-scala-2-11.md | 0 docs/src/{ => wiki}/width-inference.md | 0 38 files changed, 27 insertions(+), 11 deletions(-) rename docs/src/{ => wiki}/annotations.md (100%) rename docs/src/{ => wiki}/blackboxes.md (100%) rename docs/src/{ => wiki}/bundles-and-vecs.md (100%) rename docs/src/{ => wiki}/chisel3-vs-chisel2.md (100%) rename docs/src/{ => wiki}/combinational-circuits.md (100%) rename docs/src/{ => wiki}/cookbook.md (100%) rename docs/src/{ => wiki}/data-types.md (100%) rename docs/src/{ => wiki}/developers.md (100%) rename docs/src/{ => wiki}/experimental-features.md (100%) rename docs/src/{ => wiki}/faqs.md (100%) rename docs/src/{ => wiki}/functional-abstraction.md (100%) rename docs/src/{ => wiki}/functional-module-creation.md (100%) rename docs/src/{ => wiki}/index.md (100%) rename docs/src/{ => wiki}/interfaces-and-connections.md (100%) rename docs/src/{ => wiki}/interval-type.md (100%) rename docs/src/{ => wiki}/introduction.md (100%) rename docs/src/{ => wiki}/memories.md (100%) rename docs/src/{ => wiki}/modules.md (100%) rename docs/src/{ => wiki}/multi-clock.md (100%) rename docs/src/{ => wiki}/muxes-and-input-selection.md (100%) rename docs/src/{ => wiki}/operators.md (100%) rename docs/src/{ => wiki}/polymorphism-and-parameterization.md (100%) rename docs/src/{ => wiki}/ports.md (100%) rename docs/src/{ => wiki}/printing.md (100%) rename docs/src/{ => wiki}/reset.md (100%) rename docs/src/{ => wiki}/resources.md (100%) rename docs/src/{ => wiki}/sbt-subproject.md (100%) rename docs/src/{ => wiki}/sequential-circuits.md (100%) rename docs/src/{ => wiki}/style.md (100%) rename docs/src/{ => wiki}/supported-hardware.md (100%) rename docs/src/{ => wiki}/test-coverage.md (100%) rename docs/src/{ => wiki}/troubleshooting.md (100%) rename docs/src/{ => wiki}/unconnected-wires.md (100%) rename docs/src/{ => wiki}/upgrading-from-scala-2-11.md (100%) rename docs/src/{ => wiki}/width-inference.md (100%) diff --git a/.circleci/config.yml b/.circleci/config.yml index 3fac3c38496..bc0814505a2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -139,6 +139,17 @@ jobs: - .m2 - .sbt + test-chisel-docs: + executor: chisel-executor + steps: + - attach_workspace: + at: /home/chisel + + - run: + command: | + date > date.treadle + (sbt $SBT_ARGS "docs/mdoc") + test-chisel-2_11: executor: chisel-executor steps: diff --git a/README.md b/README.md index ad6c5fddafb..49f37965711 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![Chisel 3](https://raw.githubusercontent.com/freechipsproject/chisel3/master/doc/images/chisel_logo.svg?sanitize=true) +![Chisel 3](https://raw.githubusercontent.com/freechipsproject/chisel3/master/docs/src/images/chisel_logo.svg?sanitize=true) --- @@ -26,7 +26,7 @@ Chisel is powered by [FIRRTL (Flexible Intermediate Representation for RTL)](htt Consider an FIR filter that implements a convolution operation, as depicted in this block diagram: - + While Chisel provides similar base primitives as synthesizable Verilog, and *could* be used as such: diff --git a/docs/README.md b/docs/README.md index 2b7e293de97..23ef67f2247 100644 --- a/docs/README.md +++ b/docs/README.md @@ -8,16 +8,21 @@ 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. -For each topic, we categorize documentation as described in +Previous Wiki documentation, now hosted by the website, is contained in the `src/wiki` directory. +We are in the process of converting this documentation into the four categories as described in [Divio's documentation system](https://documentation.divio.com/). -These directories contain 3 documentation types: -* Tutorials -* Explanation -* How-To Guides +The four documentation types are: + 1. Reference (source code scaladoc) + 1. Explanation (`src/explanations`) + 1. How-To Guides (`src/cookbooks`) + 1. Tutorials (currently not located here) -Note that the 4th documentation type, "Reference", is omitted here. -We are working on generating API documentation from the code. - -## Topic Table of Contents: +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` directory and is being incrementally converted to these categories. +This documentation is hosted on the Chisel [website](https://www.chisel-lang.org). diff --git a/docs/src/annotations.md b/docs/src/wiki/annotations.md similarity index 100% rename from docs/src/annotations.md rename to docs/src/wiki/annotations.md diff --git a/docs/src/blackboxes.md b/docs/src/wiki/blackboxes.md similarity index 100% rename from docs/src/blackboxes.md rename to docs/src/wiki/blackboxes.md diff --git a/docs/src/bundles-and-vecs.md b/docs/src/wiki/bundles-and-vecs.md similarity index 100% rename from docs/src/bundles-and-vecs.md rename to docs/src/wiki/bundles-and-vecs.md diff --git a/docs/src/chisel3-vs-chisel2.md b/docs/src/wiki/chisel3-vs-chisel2.md similarity index 100% rename from docs/src/chisel3-vs-chisel2.md rename to docs/src/wiki/chisel3-vs-chisel2.md diff --git a/docs/src/combinational-circuits.md b/docs/src/wiki/combinational-circuits.md similarity index 100% rename from docs/src/combinational-circuits.md rename to docs/src/wiki/combinational-circuits.md diff --git a/docs/src/cookbook.md b/docs/src/wiki/cookbook.md similarity index 100% rename from docs/src/cookbook.md rename to docs/src/wiki/cookbook.md diff --git a/docs/src/data-types.md b/docs/src/wiki/data-types.md similarity index 100% rename from docs/src/data-types.md rename to docs/src/wiki/data-types.md diff --git a/docs/src/developers.md b/docs/src/wiki/developers.md similarity index 100% rename from docs/src/developers.md rename to docs/src/wiki/developers.md diff --git a/docs/src/experimental-features.md b/docs/src/wiki/experimental-features.md similarity index 100% rename from docs/src/experimental-features.md rename to docs/src/wiki/experimental-features.md diff --git a/docs/src/faqs.md b/docs/src/wiki/faqs.md similarity index 100% rename from docs/src/faqs.md rename to docs/src/wiki/faqs.md diff --git a/docs/src/functional-abstraction.md b/docs/src/wiki/functional-abstraction.md similarity index 100% rename from docs/src/functional-abstraction.md rename to docs/src/wiki/functional-abstraction.md diff --git a/docs/src/functional-module-creation.md b/docs/src/wiki/functional-module-creation.md similarity index 100% rename from docs/src/functional-module-creation.md rename to docs/src/wiki/functional-module-creation.md diff --git a/docs/src/index.md b/docs/src/wiki/index.md similarity index 100% rename from docs/src/index.md rename to docs/src/wiki/index.md diff --git a/docs/src/interfaces-and-connections.md b/docs/src/wiki/interfaces-and-connections.md similarity index 100% rename from docs/src/interfaces-and-connections.md rename to docs/src/wiki/interfaces-and-connections.md diff --git a/docs/src/interval-type.md b/docs/src/wiki/interval-type.md similarity index 100% rename from docs/src/interval-type.md rename to docs/src/wiki/interval-type.md diff --git a/docs/src/introduction.md b/docs/src/wiki/introduction.md similarity index 100% rename from docs/src/introduction.md rename to docs/src/wiki/introduction.md diff --git a/docs/src/memories.md b/docs/src/wiki/memories.md similarity index 100% rename from docs/src/memories.md rename to docs/src/wiki/memories.md diff --git a/docs/src/modules.md b/docs/src/wiki/modules.md similarity index 100% rename from docs/src/modules.md rename to docs/src/wiki/modules.md diff --git a/docs/src/multi-clock.md b/docs/src/wiki/multi-clock.md similarity index 100% rename from docs/src/multi-clock.md rename to docs/src/wiki/multi-clock.md diff --git a/docs/src/muxes-and-input-selection.md b/docs/src/wiki/muxes-and-input-selection.md similarity index 100% rename from docs/src/muxes-and-input-selection.md rename to docs/src/wiki/muxes-and-input-selection.md diff --git a/docs/src/operators.md b/docs/src/wiki/operators.md similarity index 100% rename from docs/src/operators.md rename to docs/src/wiki/operators.md diff --git a/docs/src/polymorphism-and-parameterization.md b/docs/src/wiki/polymorphism-and-parameterization.md similarity index 100% rename from docs/src/polymorphism-and-parameterization.md rename to docs/src/wiki/polymorphism-and-parameterization.md diff --git a/docs/src/ports.md b/docs/src/wiki/ports.md similarity index 100% rename from docs/src/ports.md rename to docs/src/wiki/ports.md diff --git a/docs/src/printing.md b/docs/src/wiki/printing.md similarity index 100% rename from docs/src/printing.md rename to docs/src/wiki/printing.md diff --git a/docs/src/reset.md b/docs/src/wiki/reset.md similarity index 100% rename from docs/src/reset.md rename to docs/src/wiki/reset.md diff --git a/docs/src/resources.md b/docs/src/wiki/resources.md similarity index 100% rename from docs/src/resources.md rename to docs/src/wiki/resources.md diff --git a/docs/src/sbt-subproject.md b/docs/src/wiki/sbt-subproject.md similarity index 100% rename from docs/src/sbt-subproject.md rename to docs/src/wiki/sbt-subproject.md diff --git a/docs/src/sequential-circuits.md b/docs/src/wiki/sequential-circuits.md similarity index 100% rename from docs/src/sequential-circuits.md rename to docs/src/wiki/sequential-circuits.md diff --git a/docs/src/style.md b/docs/src/wiki/style.md similarity index 100% rename from docs/src/style.md rename to docs/src/wiki/style.md diff --git a/docs/src/supported-hardware.md b/docs/src/wiki/supported-hardware.md similarity index 100% rename from docs/src/supported-hardware.md rename to docs/src/wiki/supported-hardware.md diff --git a/docs/src/test-coverage.md b/docs/src/wiki/test-coverage.md similarity index 100% rename from docs/src/test-coverage.md rename to docs/src/wiki/test-coverage.md diff --git a/docs/src/troubleshooting.md b/docs/src/wiki/troubleshooting.md similarity index 100% rename from docs/src/troubleshooting.md rename to docs/src/wiki/troubleshooting.md diff --git a/docs/src/unconnected-wires.md b/docs/src/wiki/unconnected-wires.md similarity index 100% rename from docs/src/unconnected-wires.md rename to docs/src/wiki/unconnected-wires.md diff --git a/docs/src/upgrading-from-scala-2-11.md b/docs/src/wiki/upgrading-from-scala-2-11.md similarity index 100% rename from docs/src/upgrading-from-scala-2-11.md rename to docs/src/wiki/upgrading-from-scala-2-11.md diff --git a/docs/src/width-inference.md b/docs/src/wiki/width-inference.md similarity index 100% rename from docs/src/width-inference.md rename to docs/src/wiki/width-inference.md From fd67da568955d45f09a31ffc57cc5094f19308ce Mon Sep 17 00:00:00 2001 From: Adam Izraelevitz Date: Fri, 21 Aug 2020 10:48:31 -0700 Subject: [PATCH 3/4] Added how to build documentation, deprecated wiki --- .gitignore | 1 + docs/README.md | 9 +++++++-- docs/src/{wiki => wiki-deprecated}/annotations.md | 0 docs/src/{wiki => wiki-deprecated}/blackboxes.md | 0 docs/src/{wiki => wiki-deprecated}/bundles-and-vecs.md | 0 docs/src/{wiki => wiki-deprecated}/chisel3-vs-chisel2.md | 0 .../{wiki => wiki-deprecated}/combinational-circuits.md | 0 docs/src/{wiki => wiki-deprecated}/cookbook.md | 0 docs/src/{wiki => wiki-deprecated}/data-types.md | 0 docs/src/{wiki => wiki-deprecated}/developers.md | 0 .../{wiki => wiki-deprecated}/experimental-features.md | 0 docs/src/{wiki => wiki-deprecated}/faqs.md | 0 .../{wiki => wiki-deprecated}/functional-abstraction.md | 0 .../functional-module-creation.md | 0 docs/src/{wiki => wiki-deprecated}/index.md | 0 .../interfaces-and-connections.md | 0 docs/src/{wiki => wiki-deprecated}/interval-type.md | 0 docs/src/{wiki => wiki-deprecated}/introduction.md | 0 docs/src/{wiki => wiki-deprecated}/memories.md | 0 docs/src/{wiki => wiki-deprecated}/modules.md | 0 docs/src/{wiki => wiki-deprecated}/multi-clock.md | 0 .../muxes-and-input-selection.md | 0 docs/src/{wiki => wiki-deprecated}/operators.md | 0 .../polymorphism-and-parameterization.md | 0 docs/src/{wiki => wiki-deprecated}/ports.md | 0 docs/src/{wiki => wiki-deprecated}/printing.md | 0 docs/src/{wiki => wiki-deprecated}/reset.md | 0 docs/src/{wiki => wiki-deprecated}/resources.md | 0 docs/src/{wiki => wiki-deprecated}/sbt-subproject.md | 0 .../src/{wiki => wiki-deprecated}/sequential-circuits.md | 0 docs/src/{wiki => wiki-deprecated}/style.md | 0 docs/src/{wiki => wiki-deprecated}/supported-hardware.md | 0 docs/src/{wiki => wiki-deprecated}/test-coverage.md | 0 docs/src/{wiki => wiki-deprecated}/troubleshooting.md | 0 docs/src/{wiki => wiki-deprecated}/unconnected-wires.md | 0 .../upgrading-from-scala-2-11.md | 0 docs/src/{wiki => wiki-deprecated}/width-inference.md | 0 37 files changed, 8 insertions(+), 2 deletions(-) rename docs/src/{wiki => wiki-deprecated}/annotations.md (100%) rename docs/src/{wiki => wiki-deprecated}/blackboxes.md (100%) rename docs/src/{wiki => wiki-deprecated}/bundles-and-vecs.md (100%) rename docs/src/{wiki => wiki-deprecated}/chisel3-vs-chisel2.md (100%) rename docs/src/{wiki => wiki-deprecated}/combinational-circuits.md (100%) rename docs/src/{wiki => wiki-deprecated}/cookbook.md (100%) rename docs/src/{wiki => wiki-deprecated}/data-types.md (100%) rename docs/src/{wiki => wiki-deprecated}/developers.md (100%) rename docs/src/{wiki => wiki-deprecated}/experimental-features.md (100%) rename docs/src/{wiki => wiki-deprecated}/faqs.md (100%) rename docs/src/{wiki => wiki-deprecated}/functional-abstraction.md (100%) rename docs/src/{wiki => wiki-deprecated}/functional-module-creation.md (100%) rename docs/src/{wiki => wiki-deprecated}/index.md (100%) rename docs/src/{wiki => wiki-deprecated}/interfaces-and-connections.md (100%) rename docs/src/{wiki => wiki-deprecated}/interval-type.md (100%) rename docs/src/{wiki => wiki-deprecated}/introduction.md (100%) rename docs/src/{wiki => wiki-deprecated}/memories.md (100%) rename docs/src/{wiki => wiki-deprecated}/modules.md (100%) rename docs/src/{wiki => wiki-deprecated}/multi-clock.md (100%) rename docs/src/{wiki => wiki-deprecated}/muxes-and-input-selection.md (100%) rename docs/src/{wiki => wiki-deprecated}/operators.md (100%) rename docs/src/{wiki => wiki-deprecated}/polymorphism-and-parameterization.md (100%) rename docs/src/{wiki => wiki-deprecated}/ports.md (100%) rename docs/src/{wiki => wiki-deprecated}/printing.md (100%) rename docs/src/{wiki => wiki-deprecated}/reset.md (100%) rename docs/src/{wiki => wiki-deprecated}/resources.md (100%) rename docs/src/{wiki => wiki-deprecated}/sbt-subproject.md (100%) rename docs/src/{wiki => wiki-deprecated}/sequential-circuits.md (100%) rename docs/src/{wiki => wiki-deprecated}/style.md (100%) rename docs/src/{wiki => wiki-deprecated}/supported-hardware.md (100%) rename docs/src/{wiki => wiki-deprecated}/test-coverage.md (100%) rename docs/src/{wiki => wiki-deprecated}/troubleshooting.md (100%) rename docs/src/{wiki => wiki-deprecated}/unconnected-wires.md (100%) rename docs/src/{wiki => wiki-deprecated}/upgrading-from-scala-2-11.md (100%) rename docs/src/{wiki => wiki-deprecated}/width-inference.md (100%) diff --git a/.gitignore b/.gitignore index 5e7271513a3..27d7d702610 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ generated/ .idea_modules/ .project target/ +docs-target/ *.iml *.swp *.fir diff --git a/docs/README.md b/docs/README.md index 23ef67f2247..0ebcd23ad27 100644 --- a/docs/README.md +++ b/docs/README.md @@ -8,7 +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` directory. +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 [Divio's documentation system](https://documentation.divio.com/). @@ -23,6 +23,11 @@ Our documentation strategy for this repository is as follows: * 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` directory and is being incrementally converted to these categories. + * Old documentation is contained in the `src/wiki-deprecated` directory and is being incrementally converted to these + categories. + +To build the documentation, run `docs/mdoc` from SBT in the root directory. The generated documents +will appear in the `docs/generated` folder. To iterate on the documentation, you can run `docs/mdoc --watch`. For +more `mdoc` instructions you can visit their [website](https://scalameta.org/mdoc/). This documentation is hosted on the Chisel [website](https://www.chisel-lang.org). diff --git a/docs/src/wiki/annotations.md b/docs/src/wiki-deprecated/annotations.md similarity index 100% rename from docs/src/wiki/annotations.md rename to docs/src/wiki-deprecated/annotations.md diff --git a/docs/src/wiki/blackboxes.md b/docs/src/wiki-deprecated/blackboxes.md similarity index 100% rename from docs/src/wiki/blackboxes.md rename to docs/src/wiki-deprecated/blackboxes.md diff --git a/docs/src/wiki/bundles-and-vecs.md b/docs/src/wiki-deprecated/bundles-and-vecs.md similarity index 100% rename from docs/src/wiki/bundles-and-vecs.md rename to docs/src/wiki-deprecated/bundles-and-vecs.md diff --git a/docs/src/wiki/chisel3-vs-chisel2.md b/docs/src/wiki-deprecated/chisel3-vs-chisel2.md similarity index 100% rename from docs/src/wiki/chisel3-vs-chisel2.md rename to docs/src/wiki-deprecated/chisel3-vs-chisel2.md diff --git a/docs/src/wiki/combinational-circuits.md b/docs/src/wiki-deprecated/combinational-circuits.md similarity index 100% rename from docs/src/wiki/combinational-circuits.md rename to docs/src/wiki-deprecated/combinational-circuits.md diff --git a/docs/src/wiki/cookbook.md b/docs/src/wiki-deprecated/cookbook.md similarity index 100% rename from docs/src/wiki/cookbook.md rename to docs/src/wiki-deprecated/cookbook.md diff --git a/docs/src/wiki/data-types.md b/docs/src/wiki-deprecated/data-types.md similarity index 100% rename from docs/src/wiki/data-types.md rename to docs/src/wiki-deprecated/data-types.md diff --git a/docs/src/wiki/developers.md b/docs/src/wiki-deprecated/developers.md similarity index 100% rename from docs/src/wiki/developers.md rename to docs/src/wiki-deprecated/developers.md diff --git a/docs/src/wiki/experimental-features.md b/docs/src/wiki-deprecated/experimental-features.md similarity index 100% rename from docs/src/wiki/experimental-features.md rename to docs/src/wiki-deprecated/experimental-features.md diff --git a/docs/src/wiki/faqs.md b/docs/src/wiki-deprecated/faqs.md similarity index 100% rename from docs/src/wiki/faqs.md rename to docs/src/wiki-deprecated/faqs.md diff --git a/docs/src/wiki/functional-abstraction.md b/docs/src/wiki-deprecated/functional-abstraction.md similarity index 100% rename from docs/src/wiki/functional-abstraction.md rename to docs/src/wiki-deprecated/functional-abstraction.md diff --git a/docs/src/wiki/functional-module-creation.md b/docs/src/wiki-deprecated/functional-module-creation.md similarity index 100% rename from docs/src/wiki/functional-module-creation.md rename to docs/src/wiki-deprecated/functional-module-creation.md diff --git a/docs/src/wiki/index.md b/docs/src/wiki-deprecated/index.md similarity index 100% rename from docs/src/wiki/index.md rename to docs/src/wiki-deprecated/index.md diff --git a/docs/src/wiki/interfaces-and-connections.md b/docs/src/wiki-deprecated/interfaces-and-connections.md similarity index 100% rename from docs/src/wiki/interfaces-and-connections.md rename to docs/src/wiki-deprecated/interfaces-and-connections.md diff --git a/docs/src/wiki/interval-type.md b/docs/src/wiki-deprecated/interval-type.md similarity index 100% rename from docs/src/wiki/interval-type.md rename to docs/src/wiki-deprecated/interval-type.md diff --git a/docs/src/wiki/introduction.md b/docs/src/wiki-deprecated/introduction.md similarity index 100% rename from docs/src/wiki/introduction.md rename to docs/src/wiki-deprecated/introduction.md diff --git a/docs/src/wiki/memories.md b/docs/src/wiki-deprecated/memories.md similarity index 100% rename from docs/src/wiki/memories.md rename to docs/src/wiki-deprecated/memories.md diff --git a/docs/src/wiki/modules.md b/docs/src/wiki-deprecated/modules.md similarity index 100% rename from docs/src/wiki/modules.md rename to docs/src/wiki-deprecated/modules.md diff --git a/docs/src/wiki/multi-clock.md b/docs/src/wiki-deprecated/multi-clock.md similarity index 100% rename from docs/src/wiki/multi-clock.md rename to docs/src/wiki-deprecated/multi-clock.md diff --git a/docs/src/wiki/muxes-and-input-selection.md b/docs/src/wiki-deprecated/muxes-and-input-selection.md similarity index 100% rename from docs/src/wiki/muxes-and-input-selection.md rename to docs/src/wiki-deprecated/muxes-and-input-selection.md diff --git a/docs/src/wiki/operators.md b/docs/src/wiki-deprecated/operators.md similarity index 100% rename from docs/src/wiki/operators.md rename to docs/src/wiki-deprecated/operators.md diff --git a/docs/src/wiki/polymorphism-and-parameterization.md b/docs/src/wiki-deprecated/polymorphism-and-parameterization.md similarity index 100% rename from docs/src/wiki/polymorphism-and-parameterization.md rename to docs/src/wiki-deprecated/polymorphism-and-parameterization.md diff --git a/docs/src/wiki/ports.md b/docs/src/wiki-deprecated/ports.md similarity index 100% rename from docs/src/wiki/ports.md rename to docs/src/wiki-deprecated/ports.md diff --git a/docs/src/wiki/printing.md b/docs/src/wiki-deprecated/printing.md similarity index 100% rename from docs/src/wiki/printing.md rename to docs/src/wiki-deprecated/printing.md diff --git a/docs/src/wiki/reset.md b/docs/src/wiki-deprecated/reset.md similarity index 100% rename from docs/src/wiki/reset.md rename to docs/src/wiki-deprecated/reset.md diff --git a/docs/src/wiki/resources.md b/docs/src/wiki-deprecated/resources.md similarity index 100% rename from docs/src/wiki/resources.md rename to docs/src/wiki-deprecated/resources.md diff --git a/docs/src/wiki/sbt-subproject.md b/docs/src/wiki-deprecated/sbt-subproject.md similarity index 100% rename from docs/src/wiki/sbt-subproject.md rename to docs/src/wiki-deprecated/sbt-subproject.md diff --git a/docs/src/wiki/sequential-circuits.md b/docs/src/wiki-deprecated/sequential-circuits.md similarity index 100% rename from docs/src/wiki/sequential-circuits.md rename to docs/src/wiki-deprecated/sequential-circuits.md diff --git a/docs/src/wiki/style.md b/docs/src/wiki-deprecated/style.md similarity index 100% rename from docs/src/wiki/style.md rename to docs/src/wiki-deprecated/style.md diff --git a/docs/src/wiki/supported-hardware.md b/docs/src/wiki-deprecated/supported-hardware.md similarity index 100% rename from docs/src/wiki/supported-hardware.md rename to docs/src/wiki-deprecated/supported-hardware.md diff --git a/docs/src/wiki/test-coverage.md b/docs/src/wiki-deprecated/test-coverage.md similarity index 100% rename from docs/src/wiki/test-coverage.md rename to docs/src/wiki-deprecated/test-coverage.md diff --git a/docs/src/wiki/troubleshooting.md b/docs/src/wiki-deprecated/troubleshooting.md similarity index 100% rename from docs/src/wiki/troubleshooting.md rename to docs/src/wiki-deprecated/troubleshooting.md diff --git a/docs/src/wiki/unconnected-wires.md b/docs/src/wiki-deprecated/unconnected-wires.md similarity index 100% rename from docs/src/wiki/unconnected-wires.md rename to docs/src/wiki-deprecated/unconnected-wires.md diff --git a/docs/src/wiki/upgrading-from-scala-2-11.md b/docs/src/wiki-deprecated/upgrading-from-scala-2-11.md similarity index 100% rename from docs/src/wiki/upgrading-from-scala-2-11.md rename to docs/src/wiki-deprecated/upgrading-from-scala-2-11.md diff --git a/docs/src/wiki/width-inference.md b/docs/src/wiki-deprecated/width-inference.md similarity index 100% rename from docs/src/wiki/width-inference.md rename to docs/src/wiki-deprecated/width-inference.md From 8b63df6a314c9c504ae74502838fbbf79843c81e Mon Sep 17 00:00:00 2001 From: Adam Izraelevitz Date: Fri, 21 Aug 2020 10:50:20 -0700 Subject: [PATCH 4/4] Fix copypasta --- .circleci/config.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index bc0814505a2..238beb09933 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -147,8 +147,7 @@ jobs: - run: command: | - date > date.treadle - (sbt $SBT_ARGS "docs/mdoc") + sbt $SBT_ARGS "docs/mdoc" test-chisel-2_11: executor: chisel-executor