BoringUtils

chisel3.util.experimental.BoringUtils
object BoringUtils

Utilities for generating synthesizable cross module references that "bore" through the hierarchy. The underlying cross module connects are handled by FIRRTL's Wiring Transform.

Consider the following example where you want to connect a component in one module to a component in another. Module Constant has a wire tied to 42 and Expect will assert unless connected to 42:

class Constant extends Module {
 val io = IO(new Bundle{})
 val x = Wire(UInt(6.W))
 x := 42.U
}
class Expect extends Module {
 val io = IO(new Bundle{})
 val y = Wire(UInt(6.W))
 y := 0.U
 // This assertion will fail unless we bore!
 chisel3.assert(y === 42.U, "y should be 42 in module Expect")
}

We can then connect x to y using BoringUtils without modifiying the Chisel IO of Constant, Expect, or modules that may instantiate them. There are two approaches to do this:

  1. Hierarchical boring using BoringUtils.bore

  2. Non-hierarchical boring using BoringUtils.addSink/BoringUtils.addSource

===Hierarchical Boring===

Hierarchical boring involves connecting one sink instance to another source instance in a parent module. Below, module Top contains an instance of Constant and Expect. Using BoringUtils.bore, we can connect constant.x to expect.y.

class Top extends Module {
 val io = IO(new Bundle{})
 val constant = Module(new Constant)
 val expect = Module(new Expect)
 BoringUtils.bore(constant.x, Seq(expect.y))
}

Bottom-up boring involves boring a sink in a child instance to the current module, where it can be assigned from. Using BoringUtils.bore, we can connect from constant.x to mywire.

class Top extends Module {
 val io = IO(new Bundle { val foo = UInt(3.W) })
 val constant = Module(new Constant)
 io.foo := BoringUtils.bore(constant.x)
}

===Non-hierarchical Boring===

Non-hierarchical boring involves connections from sources to sinks that cannot see each other. Here, x is described as a source and given a name, uniqueId, and y is described as a sink with the same name. This is equivalent to the hierarchical boring example above, but requires no modifications to Top.

class Constant extends Module {
 val io = IO(new Bundle{})
 val x = Wire(UInt(6.W))
 x := 42.U
 BoringUtils.addSource(x, "uniqueId")
}
class Expect extends Module {
 val io = IO(new Bundle{})
 val y = Wire(UInt(6.W))
 y := 0.U
 // This assertion will fail unless we bore!
 chisel3.assert(y === 42.U, "y should be 42 in module Expect")
 BoringUtils.addSink(y, "uniqueId")
}
class Top extends Module {
 val io = IO(new Bundle{})
 val constant = Module(new Constant)
 val expect = Module(new Expect)
}

==Comments==

Both hierarchical and non-hierarchical boring emit FIRRTL annotations that describe sources and sinks. These are matched by a name key that indicates they should be wired together. Hierarchical boring safely generates this name automatically. Non-hierarchical boring unsafely relies on user input to generate this name. Use of non-hierarchical naming may result in naming conflicts that the user must handle.

The automatic generation of hierarchical names relies on a global, mutable namespace. This is currently persistent across circuit elaborations.

Attributes

Source
BoringUtils.scala
Graph
Supertypes
class Object
trait Matchable
class Any
Self type

Members list

Value members

Concrete methods

def bore[A <: Data](source: A)(implicit si: SourceInfo): A

Access a source Data that may or may not be in the current module. If this is in a child module, then create ports to allow access to the requested source.

Access a source Data that may or may not be in the current module. If this is in a child module, then create ports to allow access to the requested source.

Attributes

Source
BoringUtils.scala
def drive[A <: Data](sink: A)(implicit si: SourceInfo): A

Access a sink Data for driving that may or may not be in the current module.

Access a sink Data for driving that may or may not be in the current module.

If the sink is in a child module, than create input ports to allow driving the requested sink.

Note that the sink may not be a probe, and rwTap should be used instead.

Attributes

Source
BoringUtils.scala
def rwTap[A <: Data](source: A)(implicit si: SourceInfo): A

Access a source Data that may or may not be in the current module. If this is in a child module, then create write-only probe ports to allow access to the requested source. Supports downward accesses only.

Access a source Data that may or may not be in the current module. If this is in a child module, then create write-only probe ports to allow access to the requested source. Supports downward accesses only.

Returns a probe Data type.

Attributes

Source
BoringUtils.scala
def tap[A <: Data](source: A)(implicit si: SourceInfo): A

Access a source Data that may or may not be in the current module. If this is in a child module, then create read-only probe ports to allow access to the requested source.

Access a source Data that may or may not be in the current module. If this is in a child module, then create read-only probe ports to allow access to the requested source.

Returns a probe Data type.

Attributes

Source
BoringUtils.scala
def tapAndRead[A <: Data](source: A)(implicit si: SourceInfo): A

Access a source Data that may or may not be in the current module. If this is in a child module, then create read-only probe ports to allow access to the requested source.

Access a source Data that may or may not be in the current module. If this is in a child module, then create read-only probe ports to allow access to the requested source.

Returns a non-probe Data type.

Attributes

Source
BoringUtils.scala

Deprecated methods

def addSink(component: InstanceId, name: String, disableDedup: Boolean = ..., forceExists: Boolean = ...): Unit

Add a named sink cross module reference. Multiple sinks may map to the same source.

Add a named sink cross module reference. Multiple sinks may map to the same source.

Value parameters

component

sink circuit component

disableDedup

disable deduplication of this sink component (this should be true if you are trying to wire specific, identical sinks differently)

forceExists

if true, require that the provided name parameter already exists in the global namespace

name

unique identifier for this sink that must resolve to

Attributes

Throws
BoringUtilsException

if name is expected to exist and it doesn't

Deprecated
[Since version Chisel 6.0] Please use the new Boring API instead (BoringUtils.bore(source)). This will be removed in Chisel 7.0
Source
BoringUtils.scala
def addSource(component: NamedComponent, name: String, disableDedup: Boolean = ..., uniqueName: Boolean = ...): String

Add a named source cross module reference

Add a named source cross module reference

Value parameters

component

source circuit component

disableDedup

disable deduplication of this source component (this should be true if you are trying to wire from specific identical sources differently)

name

unique identifier for this source

uniqueName

if true, this will use a non-conflicting name from the global namespace

Attributes

Returns

the name used

Note

if a uniqueName is not specified, the returned name may differ from the user-provided name

Deprecated
[Since version Chisel 6.0] Please use the new Boring API instead (BoringUtils.bore(source)). This will be removed in Chisel 7.0
Source
BoringUtils.scala
def bore(source: Data, sinks: Seq[Data]): String

Connect a source to one or more sinks

Connect a source to one or more sinks

Value parameters

sinks

one or more sink components

source

a source component

Attributes

Returns

the name of the signal used to connect the source to the sinks

Note

the returned name will be based on the name of the source component

Deprecated
[Since version Chisel 6.0] Please use the new Boring API instead (BoringUtils.bore(source)). This will be removed in Chisel 7.0
Source
BoringUtils.scala