Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions core/src/main/scala/chisel3/BlackBox.scala
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ import scala.collection.mutable
* }}}
* @note The parameters API is experimental and may change
*/
@deprecated(
"use `chisel3.ExtModule` instead. To migrate replace `val io = { ... }` with `val io = FlatIO { ... }`, `object io { ... }; locally { io }`, or manually flatten your IO as `ExtModule` allows calling `IO` more than once.",
"7.5.0"
)
abstract class BlackBox(
val params: Map[String, Param] = Map.empty[String, Param],
override protected final val knownLayers: Seq[Layer] = Seq.empty[Layer]
Expand Down
3 changes: 2 additions & 1 deletion core/src/main/scala/chisel3/Module.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

package chisel3

import scala.annotation.nowarn
import scala.collection.immutable.{ListMap, VectorBuilder}
import scala.collection.mutable.{ArrayBuffer, HashMap, LinkedHashSet}

Expand Down Expand Up @@ -370,7 +371,7 @@ package internal {
// currentModule (and not clonePorts)
val clonePorts = proto match {
// BlackBox needs special handling for its pseduo-io Bundle
case b: BlackBox =>
case b: BlackBox @nowarn("cat=deprecation") =>
new ClonePorts(dataPorts :+ ("io" -> b._io.get): _*)
case _ => new ClonePorts(dataPorts: _*)
}
Expand Down
7 changes: 0 additions & 7 deletions core/src/main/scala/chisel3/experimental/ExtModule.scala
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,6 @@ private[chisel3] object BlackBoxHelpers {
}
import BlackBoxHelpers.BlackBoxInlineAnnoHelpers

private object ExtModule {
final val deprecatedCaseClass =
"this has moved from `chisel3.experimental` to `chisel3` and all `case class` methods are deprecated. This will be made a `class` in Chisel 8."
final val since = "7.5.0"
}
import ExtModule._

/** Parameters for BlackBoxes */
@deprecated(deprecatedCaseClass, since)
abstract class Param
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import chisel3.internal.firrtl.ir.{Component, ModuleCloneIO, Ref}
import chisel3.internal.{throwException, Namespace}
import chisel3.layer.Layer
import chisel3._
import scala.annotation.nowarn

// Private internal class to serve as a _parent for Data in cloned ports
private[chisel3] class ModuleClone[T <: BaseModule](val getProto: T)(implicit si: SourceInfo)
Expand Down Expand Up @@ -37,7 +38,7 @@ private[chisel3] class ModuleClone[T <: BaseModule](val getProto: T)(implicit si
private[chisel3] lazy val ioMap: Map[Data, Data] = {
getProto match {
// BlackBox needs special handling for its pseduo-io Bundle
case protoBB: BlackBox =>
case protoBB: BlackBox @nowarn("cat=deprecation") =>
Map(protoBB._io.get -> getPorts._elements("io"))
case _ =>
val name2Port = getPorts._elements
Expand All @@ -64,7 +65,7 @@ private[chisel3] class ModuleClone[T <: BaseModule](val getProto: T)(implicit si
record.setRef(ref, force = true) // force because we did .forceName first
getProto match {
// BlackBox needs special handling for its pseduo-io Bundle
case _: BlackBox =>
case _: BlackBox @nowarn("cat=deprecation") =>
// Override the io Bundle's ref so that it thinks it is the top for purposes of
// generating FIRRTL
record._elements("io").setRef(ref, force = true)
Expand Down
5 changes: 3 additions & 2 deletions core/src/main/scala/chisel3/internal/BiConnect.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import chisel3.internal.Builder.pushCommand
import chisel3.internal.firrtl.ir.{Connect, DefInvalid}
import chisel3.internal.firrtl.Converter
import chisel3.internal.MonoConnect.reportIfReadOnly
import scala.annotation.nowarn

import _root_.firrtl.passes.CheckTypes

Expand Down Expand Up @@ -309,8 +310,8 @@ private[chisel3] object BiConnect {

// do not bulk connect the 'io' pseudo-bundle of a BlackBox since it will be decomposed in FIRRTL
def blackBoxCheck = Seq(source, sink).map(_._parent).forall {
case Some(_: BlackBox) => false
case _ => true
case Some(_: BlackBox @nowarn("cat=deprecation")) => false
case _ => true
}

typeCheck && contextCheck && bindingCheck && flowSinkCheck && flowSourceCheck && sourceAndSinkNotLiteralOrViewCheck && blackBoxCheck
Expand Down
1 change: 0 additions & 1 deletion docs/src/appendix/experimental-features.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ Chisel has a number of new features that are worth checking out. This page is a
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
Expand Down
12 changes: 5 additions & 7 deletions docs/src/cookbooks/cookbook.md
Original file line number Diff line number Diff line change
Expand Up @@ -980,16 +980,14 @@ chisel3.docs.emitSystemVerilog(new Foo2)

### 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:
You can override the `desiredName` function. This works with normal Chisel modules and external modules. 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))
})
class Coffee extends ExtModule {
val I = IO(Input(UInt(32.W)))
val O = IO(Output(UInt(32.W)))
override def desiredName = "Tea"
}

Expand All @@ -998,7 +996,7 @@ class Salt extends Module {
val drink = Module(new Coffee)
override def desiredName = "SodiumMonochloride"

drink.io.I := 42.U
drink.I := 42.U
}
```

Expand Down
93 changes: 41 additions & 52 deletions docs/src/explanations/blackboxes.md
Original file line number Diff line number Diff line change
@@ -1,46 +1,44 @@
---
layout: docs
title: "Blackboxes"
title: |
External Modules ("Black Boxes")
section: "chisel3"
---

# BlackBoxes
# External Modules ("Black Boxes")

Chisel *BlackBoxes* are used to instantiate externally defined modules. This construct is useful
Chisel *External Modules* 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
Modules defined as an `ExtModule` 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_`).
Unlike Module, `ExtModule` has no implicit clock and reset.
Instead, they behave like `RawModule` in this regard.
`ExtModule`'s clock and reset ports must be explicitly declared and connected to input signals.

### Parameterization

Verilog parameters can be passed as an argument to the BlackBox constructor.
Verilog parameters can be passed as an argument to the `ExtModule` 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
import chisel3.experimental.fromStringToStringParam

class IBUFDS extends BlackBox(Map("DIFF_TERM" -> "TRUE",
class IBUFDS extends ExtModule(Map("DIFF_TERM" -> "TRUE",
"IOSTANDARD" -> "DEFAULT")) {
val io = IO(new Bundle {
val O = Output(Clock())
val I = Input(Clock())
val IB = Input(Clock())
})
val O = IO(Output(Clock()))
val I = IO(Input(Clock()))
val IB = IO(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
ibufds.I := clock
}
```

Expand All @@ -54,26 +52,24 @@ IBUFDS #(.DIFF_TERM("TRUE"), .IOSTANDARD("DEFAULT")) ibufds (
);
```

### Providing Implementations for Blackboxes
### Providing Implementations for External Modules

Chisel provides the following ways of delivering the code underlying the blackbox. Consider the following blackbox that
Chisel provides the following ways of delivering the code underlying the external module. Consider the following external module 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))
})
class ExtModuleRealAdd extends ExtModule {
val in1 = IO(Input(UInt(64.W)))
val in2 = IO(Input(UInt(64.W)))
val out = IO(Output(UInt(64.W)))
}
```

The implementation is described by the following verilog

```verilog
module BlackBoxRealAdd(
module ExtModuleRealAdd(
input [63:0] in1,
input [63:0] in2,
output reg [63:0] out
Expand All @@ -84,20 +80,17 @@ module BlackBoxRealAdd(
endmodule
```

### Blackboxes with Verilog in a Resource File
### External Modules with Verilog in a Resource File

In order to deliver the verilog snippet above to the backend simulator, chisel3 provides the following tools based on the chisel/firrtl [annotation system](../explanations/annotations). Add the trait `HasBlackBoxResource` to the declaration, and then call a function in the body to say where the system can find the verilog. The Module now looks like
In order to deliver the Verilog snippet above to the backend simulator, chisel3 provides the following tools basedf on the Chisel/FIRRTL [annotation system](../explanations/annotations) via methods that are already available on `ExtModule`. To include a Java resource, use `addResource`:

```scala mdoc:silent:reset
import chisel3._
import chisel3.util.HasBlackBoxResource

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))
})

class ExtModuleRealAdd extends ExtModule {
val in1 = IO(Input(UInt(64.W)))
val in2 = IO(Input(UInt(64.W)))
val out = IO(Output(UInt(64.W)))
addResource("/real_math.v")
}
```
Expand All @@ -107,21 +100,18 @@ The verilog snippet above gets put into a resource file names `real_math.v`. Wh
Chisel project, see [chisel-template](https://github.com/chipsalliance/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.
### External Modules with In-line Verilog
It is also possible to place this Verilog directly in the scala source. Instead
of `addResource` 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(
class ExtModuleRealAdd extends ExtModule {
val in1 = IO(Input(UInt(64.W)))
val in2 = IO(Input(UInt(64.W)))
val out = IO(Output(UInt(64.W)))
setInline("ExtModuleRealAdd.v",
"""module ExtModuleRealAdd(
| input [63:0] in1,
| input [63:0] in2,
| output reg [63:0] out
Expand All @@ -134,16 +124,15 @@ class BlackBoxRealAdd extends BlackBox with HasBlackBoxInline {
}
```

This technique will copy the inline verilog into the target directory under the name `BlackBoxRealAdd.v`
This technique will copy the inline verilog into the target directory under the name `ExtModuleRealAdd.v`

### Under the Hood
This mechanism of delivering verilog content to the testing backends is implemented via chisel/firrtl annotations. The
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
`addResource` 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.

9 changes: 4 additions & 5 deletions docs/src/explanations/dataview.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class my_module extends RawModule {
```

Expressing something that matches a standard Verilog interface is important when instantiating Verilog
modules in a Chisel design as `BlackBoxes`.
modules in a Chisel design as `ExtModule`s.
Generally though, Chisel developers prefer to use composition via utilities like `Decoupled` rather
than a flat handling of `ready` and `valid` as in the above.
A more "Chisel-y" implementation of this interface might look like:
Expand Down Expand Up @@ -266,7 +266,7 @@ import chisel3._
import chisel3.experimental.dataview._
```

A `DataView` is _total_ if all fields of the _Target_ type and all fields of the _View_ type are
A `DataView` is _total_ if all fields of the _Target_ type and all fields of the _View_ type are
included in the mapping.
Chisel will error if a field is accidentally left out from a `DataView`.
For example:
Expand Down Expand Up @@ -341,7 +341,7 @@ polymorphic code.
They are a common feature in "modern programming languages" like
Scala,
Swift (see [protocols](https://docs.swift.org/swift-book/LanguageGuide/Protocols.html)),
and Rust (see [traits](https://doc.rust-lang.org/book/ch10-02-traits.html)).
and Rust (see [traits](https://doc.rust-lang.org/book/ch10-02-traits.html)).
Type classes may appear similar to inheritance in object-oriented programming but there are some
important differences:

Expand Down Expand Up @@ -377,7 +377,7 @@ before looking in the _implicit scope_.
* Companion object of a type
* Implicit scope of an argument's type
* Implicit scope of type parameters

If at either stage, multiple implicits are found, then the static overloading rule is used to resolve
it.
Put simply, if one implicit applies to a more-specific type than the other, the more-specific one
Expand Down Expand Up @@ -510,4 +510,3 @@ This is how Chisel is able to check for totality as [described above](#totality-
In addition to checking if a user has left a field out of the mapping, it also allows Chisel to check
if the user has included a `Data` in the mapping that isn't actually a part of the _target_ nor the
_view_.

2 changes: 1 addition & 1 deletion docs/src/explanations/modules.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,4 +129,4 @@ modules, then using `withClockAndReset(clock, !rstn)` we can use an active low
reset in the entire design.

The clock is just wired as is, but if needed, `RawModule` can be used in
conjunction with `BlackBox` to connect a differential clock input for example.
conjunction with `ExtModule` to connect a differential clock input for example.
2 changes: 1 addition & 1 deletion docs/src/explanations/ports.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ provide powerful wiring constructs described later.

(Chisel 3.2+)

Chisel 3.2 introduced `DataMirror.modulePorts` which can be used to inspect the IOs of any Chisel module (this includes modules in both `import chisel3._` and `import Chisel._`, as well as BlackBoxes from each package).
Chisel 3.2 introduced `DataMirror.modulePorts` which can be used to inspect the IOs of any Chisel module (this includes modules in both `import chisel3._` and `import Chisel._`, as well as external modules from each package).
Here is an example of how to use this API:

```scala mdoc
Expand Down
11 changes: 11 additions & 0 deletions src/main/scala-2/chisel3/interface/Interface.scala
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,24 @@ trait Interface extends InterfaceCommon { self: Singleton =>
/** The black box that has the same ports as this interface. This is what is
* instantiated by any user of this interface, i.e., a test harness.
*/
@deprecated("use `ExtModule` instead", "7.5.0")
final class BlackBox extends chisel3.BlackBox with Entity {
final val io = IO(ports)

/** Return the properties of this instance. This requires brining a conformance into scope. */
override final def properties[B <: BaseModule: Conformance]: Properties = implicitly[Conformance[B]].properties
}

/** The black box that has the same ports as this interface. This is what is
* instantiated by any user of this interface, i.e., a test harness.
*/
final class ExtModule extends chisel3.ExtModule with Entity {
final val io = FlatIO(ports)

/** Return the properties of this instance. This requires brining a conformance into scope. */
override final def properties[B <: BaseModule: Conformance]: Properties = implicitly[Conformance[B]].properties
}

/** The module that wraps any module which conforms to this Interface.
*/
final class Module[B <: BaseModule](
Expand Down
Loading