Skip to content

Commit 646af55

Browse files
committed
[core] Deprecate BlackBox in favor of ExtModule
Deprecate BlackBox and tell users to switch to ExtModule. BlackBox has a ton of baggage associated with it, due to it mandating, at runtime, a single `val io` call and no additional calls to `IO` while also magically removing the `io_` prefix in the generated FIRRTL. `ExtModule` is far cleaner and works as a user would expect. You can call `IO` as much as you want. No magic prefixing happens. This is slightly unfortunate as one could argue that `BlackBox` is a good name. However, you can also argue (more strongly I would add) that this is an "external module" and it would be better to call it as such. If this is controversial, we can consider a migration back from `ExtModule` to `BlackBox`. Migrate some tests that were only testing blackboxes to be duplicated in the external module tests. This will allow us to just delete this test later. This has three motivations: 1. `BlackBox` has always been janky for the reasons above and `ExtModule` is the saner generator API. 2. It's bad to have two similar, though subtly different ways of doing things. 3. The singular IO that `BlackBox` forces users to go through means that `BlackBox` cannot have domain information attached to it. This essentially means that `BlackBox` will be essentially unusable until domains gain support for being in subfields. It's easier to just deprecate `BlackBox` than to require that domains gain this complicated feature addition just now. Signed-off-by: Schuyler Eldridge <[email protected]>
1 parent 969a052 commit 646af55

File tree

24 files changed

+265
-68
lines changed

24 files changed

+265
-68
lines changed

core/src/main/scala/chisel3/BlackBox.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ import scala.collection.mutable
4646
* }}}
4747
* @note The parameters API is experimental and may change
4848
*/
49+
@deprecated(
50+
"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.",
51+
"7.5.0"
52+
)
4953
abstract class BlackBox(
5054
val params: Map[String, Param] = Map.empty[String, Param],
5155
override protected final val knownLayers: Seq[Layer] = Seq.empty[Layer]

core/src/main/scala/chisel3/Module.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
package chisel3
44

5+
import scala.annotation.nowarn
56
import scala.collection.immutable.{ListMap, VectorBuilder}
67
import scala.collection.mutable.{ArrayBuffer, HashMap, LinkedHashSet}
78

@@ -370,7 +371,7 @@ package internal {
370371
// currentModule (and not clonePorts)
371372
val clonePorts = proto match {
372373
// BlackBox needs special handling for its pseduo-io Bundle
373-
case b: BlackBox =>
374+
case b: BlackBox @nowarn("cat=deprecation") =>
374375
new ClonePorts(dataPorts :+ ("io" -> b._io.get): _*)
375376
case _ => new ClonePorts(dataPorts: _*)
376377
}

core/src/main/scala/chisel3/experimental/hierarchy/ModuleClone.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import chisel3.internal.firrtl.ir.{Component, ModuleCloneIO, Ref}
88
import chisel3.internal.{throwException, Namespace}
99
import chisel3.layer.Layer
1010
import chisel3._
11+
import scala.annotation.nowarn
1112

1213
// Private internal class to serve as a _parent for Data in cloned ports
1314
private[chisel3] class ModuleClone[T <: BaseModule](val getProto: T)(implicit si: SourceInfo)
@@ -37,7 +38,7 @@ private[chisel3] class ModuleClone[T <: BaseModule](val getProto: T)(implicit si
3738
private[chisel3] lazy val ioMap: Map[Data, Data] = {
3839
getProto match {
3940
// BlackBox needs special handling for its pseduo-io Bundle
40-
case protoBB: BlackBox =>
41+
case protoBB: BlackBox @nowarn("cat=deprecation") =>
4142
Map(protoBB._io.get -> getPorts._elements("io"))
4243
case _ =>
4344
val name2Port = getPorts._elements
@@ -64,7 +65,7 @@ private[chisel3] class ModuleClone[T <: BaseModule](val getProto: T)(implicit si
6465
record.setRef(ref, force = true) // force because we did .forceName first
6566
getProto match {
6667
// BlackBox needs special handling for its pseduo-io Bundle
67-
case _: BlackBox =>
68+
case _: BlackBox @nowarn("cat=deprecation") =>
6869
// Override the io Bundle's ref so that it thinks it is the top for purposes of
6970
// generating FIRRTL
7071
record._elements("io").setRef(ref, force = true)

core/src/main/scala/chisel3/internal/BiConnect.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import chisel3.internal.Builder.pushCommand
1111
import chisel3.internal.firrtl.ir.{Connect, DefInvalid}
1212
import chisel3.internal.firrtl.Converter
1313
import chisel3.internal.MonoConnect.reportIfReadOnly
14+
import scala.annotation.nowarn
1415

1516
import _root_.firrtl.passes.CheckTypes
1617

@@ -309,8 +310,8 @@ private[chisel3] object BiConnect {
309310

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

316317
typeCheck && contextCheck && bindingCheck && flowSinkCheck && flowSourceCheck && sourceAndSinkNotLiteralOrViewCheck && blackBoxCheck

src/main/scala-2/chisel3/interface/Interface.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,13 +95,24 @@ trait Interface extends InterfaceCommon { self: Singleton =>
9595
/** The black box that has the same ports as this interface. This is what is
9696
* instantiated by any user of this interface, i.e., a test harness.
9797
*/
98+
@deprecated("use `ExtModule` instead", "7.5.0")
9899
final class BlackBox extends chisel3.BlackBox with Entity {
99100
final val io = IO(ports)
100101

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

106+
/** The black box that has the same ports as this interface. This is what is
107+
* instantiated by any user of this interface, i.e., a test harness.
108+
*/
109+
final class ExtModule extends chisel3.ExtModule with Entity {
110+
final val io = FlatIO(ports)
111+
112+
/** Return the properties of this instance. This requires brining a conformance into scope. */
113+
override final def properties[B <: BaseModule: Conformance]: Properties = implicitly[Conformance[B]].properties
114+
}
115+
105116
/** The module that wraps any module which conforms to this Interface.
106117
*/
107118
final class Module[B <: BaseModule](

src/main/scala/chisel3/util/BlackBoxUtils.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,14 @@ import chisel3._
66
import chisel3.experimental.BlackBoxHelpers.BlackBoxInlineAnnoHelpers
77
import firrtl.transforms.{BlackBoxInlineAnno, BlackBoxNotFoundException, BlackBoxPathAnno}
88

9+
private object BlackBoxUtils {
10+
final val message =
11+
"this trait will be removed in Chisel 8, please switch from `BlackBox` to `ExtModule` which has the methods of this trait already available"
12+
final val since = "7.5.0"
13+
}
14+
import BlackBoxUtils._
15+
16+
@deprecated(message, since)
917
trait HasBlackBoxResource extends BlackBox {
1018
self: BlackBox =>
1119

@@ -23,6 +31,7 @@ trait HasBlackBoxResource extends BlackBox {
2331
}
2432
}
2533

34+
@deprecated(message, since)
2635
trait HasBlackBoxInline extends BlackBox {
2736
self: BlackBox =>
2837

@@ -36,6 +45,7 @@ trait HasBlackBoxInline extends BlackBox {
3645
}
3746
}
3847

48+
@deprecated(message, since)
3949
trait HasBlackBoxPath extends BlackBox {
4050
self: BlackBox =>
4151

src/test/scala-2/chiselTests/AnalogIntegrationSpec.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
package chiselTests
44

55
import chisel3._
6+
import chisel3.experimental.{attach, Analog}
67
import chisel3.util._
78
import chisel3.simulator.scalatest.ChiselSim
89
import chisel3.simulator.stimulus.RunUntilFinished
9-
import chisel3.experimental._
1010
import org.scalatest.flatspec.AnyFlatSpec
1111

1212
/* This test is different from AnalogSpec in that it uses more complicated black boxes that can each
@@ -29,8 +29,8 @@ class AnalogBlackBoxIO(val n: Int) extends Bundle {
2929

3030
// Assigns bus to out
3131
// Assigns in.bits + index to bus when in.valid
32-
class AnalogBlackBox(index: Int) extends BlackBox(Map("index" -> index)) with HasBlackBoxResource {
33-
val io = IO(new AnalogBlackBoxIO(1))
32+
class AnalogBlackBox(index: Int) extends ExtModule(Map("index" -> index)) {
33+
val io = FlatIO(new AnalogBlackBoxIO(1))
3434

3535
addResource("/chisel3/AnalogBlackBox.v")
3636
}

src/test/scala-2/chiselTests/AnalogSpec.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,23 +27,23 @@ trait AnalogReader {
2727
def bus: Analog
2828
}
2929

30-
class AnalogReaderBlackBox extends BlackBox with AnalogReader with HasBlackBoxResource {
31-
val io = IO(new AnalogReaderIO)
30+
class AnalogReaderBlackBox extends ExtModule with AnalogReader {
31+
val io = FlatIO(new AnalogReaderIO)
3232
def out = io.out
3333
def bus = io.bus
3434

3535
addResource("/chisel3/AnalogBlackBox.v")
3636
}
3737

3838
class AnalogReaderWrapper extends Module with AnalogReader {
39-
val io = IO(new AnalogReaderIO)
39+
val io = FlatIO(new AnalogReaderIO)
4040
def out = io.out
4141
def bus = io.bus
4242
val mod = Module(new AnalogReaderBlackBox)
4343
io <> mod.io
4444
}
45-
class AnalogWriterBlackBox extends BlackBox {
46-
val io = IO(new AnalogWriterIO)
45+
class AnalogWriterBlackBox extends ExtModule {
46+
val io = FlatIO(new AnalogWriterIO)
4747
}
4848
// Connects two Analog ports
4949
class AnalogConnector extends Module {

src/test/scala-2/chiselTests/BlackBox.scala

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ import chisel3.testing.scalatest.FileCheck
1212
import chisel3.util._
1313
import org.scalatest.flatspec.AnyFlatSpec
1414
import org.scalatest.matchers.should.Matchers
15+
import scala.annotation.nowarn
1516

17+
@nowarn("cat=deprecation")
1618
class BlackBoxInverter extends BlackBox with HasBlackBoxResource {
1719
val io = IO(new Bundle() {
1820
val in = Input(Bool())
@@ -24,6 +26,7 @@ class BlackBoxInverter extends BlackBox with HasBlackBoxResource {
2426

2527
// Due to the removal of "val io", this technically works
2628
// This style is discouraged, please use "val io"
29+
@nowarn("cat=deprecation")
2730
class BlackBoxInverterSuggestName extends BlackBox with HasBlackBoxResource {
2831
override def desiredName: String = "BlackBoxInverter"
2932
val foo = IO(new Bundle() {
@@ -34,6 +37,7 @@ class BlackBoxInverterSuggestName extends BlackBox with HasBlackBoxResource {
3437
addResource("/chisel3/BlackBoxInverter.v")
3538
}
3639

40+
@nowarn("cat=deprecation")
3741
class BlackBoxPassthrough extends BlackBox with HasBlackBoxResource {
3842
val io = IO(new Bundle() {
3943
val in = Input(Bool())
@@ -44,6 +48,7 @@ class BlackBoxPassthrough extends BlackBox with HasBlackBoxResource {
4448
}
4549

4650
// Test Flip on top-level IO
51+
@nowarn("cat=deprecation")
4752
class BlackBoxPassthrough2 extends BlackBox with HasBlackBoxResource {
4853
val io = IO(Flipped(new Bundle() {
4954
val in = Output(Bool())
@@ -53,6 +58,7 @@ class BlackBoxPassthrough2 extends BlackBox with HasBlackBoxResource {
5358
addResource("/chisel3/BlackBoxPassthrough2.v")
5459
}
5560

61+
@nowarn("cat=deprecation")
5662
class BlackBoxRegister extends BlackBox with HasBlackBoxResource {
5763
val io = IO(new Bundle() {
5864
val clock = Input(Clock())
@@ -135,6 +141,7 @@ class BlackBoxWithClockTester extends Module {
135141
when(end) { stop() }
136142
}
137143

144+
@nowarn("cat=deprecation")
138145
class BlackBoxConstant(value: Int)
139146
extends BlackBox(Map("VALUE" -> value, "WIDTH" -> log2Ceil(value + 1)))
140147
with HasBlackBoxResource {
@@ -146,6 +153,7 @@ class BlackBoxConstant(value: Int)
146153
addResource("/chisel3/BlackBoxConstant.v")
147154
}
148155

156+
@nowarn("cat=deprecation")
149157
class BlackBoxStringParam(str: String) extends BlackBox(Map("STRING" -> str)) with HasBlackBoxResource {
150158
val io = IO(new Bundle {
151159
val out = UInt(32.W)
@@ -154,6 +162,7 @@ class BlackBoxStringParam(str: String) extends BlackBox(Map("STRING" -> str)) wi
154162
addResource("/chisel3/BlackBoxStringParam.v")
155163
}
156164

165+
@nowarn("cat=deprecation")
157166
class BlackBoxRealParam(dbl: Double) extends BlackBox(Map("REAL" -> dbl)) with HasBlackBoxResource {
158167
val io = IO(new Bundle {
159168
val out = UInt(64.W)
@@ -162,6 +171,7 @@ class BlackBoxRealParam(dbl: Double) extends BlackBox(Map("REAL" -> dbl)) with H
162171
addResource("/chisel3/BlackBoxRealParam.v")
163172
}
164173

174+
@nowarn("cat=deprecation")
165175
class BlackBoxTypeParam(w: Int, raw: String) extends BlackBox(Map("T" -> RawParam(raw))) with HasBlackBoxResource {
166176
val io = IO(new Bundle {
167177
val out = UInt(w.W)
@@ -170,6 +180,7 @@ class BlackBoxTypeParam(w: Int, raw: String) extends BlackBox(Map("T" -> RawPara
170180
addResource("/chisel3/BlackBoxTypeParam.v")
171181
}
172182

183+
@nowarn("cat=deprecation")
173184
class BlackBoxNoIO extends BlackBox with HasBlackBoxResource {
174185
// Whoops! typo
175186
val ioo = IO(new Bundle {
@@ -179,6 +190,7 @@ class BlackBoxNoIO extends BlackBox with HasBlackBoxResource {
179190
addResource("/chisel3/BlackBoxNoIO.v")
180191
}
181192

193+
@nowarn("cat=deprecation")
182194
class BlackBoxUIntIO extends BlackBox with HasBlackBoxResource {
183195
val io = IO(Output(UInt(8.W)))
184196

@@ -253,7 +265,7 @@ class BlackBoxSpec extends AnyFlatSpec with Matchers with ChiselSim with FileChe
253265

254266
"A Blackbox with Flipped IO" should "work" in {
255267
class Top extends RawModule {
256-
val inst = Module(new BlackBox {
268+
val inst = Module(new BlackBox @nowarn("cat=deprecation") {
257269
override def desiredName: String = "MyBB"
258270
val io = IO(Flipped(new Bundle {
259271
val in = Bool()
@@ -289,6 +301,7 @@ class BlackBoxSpec extends AnyFlatSpec with Matchers with ChiselSim with FileChe
289301

290302
"BlackBoxes" should "sort the verilog output of their param map by param key" in {
291303

304+
@nowarn("cat=deprecation")
292305
class ParameterizedBlackBox(m: Map[String, Param]) extends BlackBox(m) {
293306
val io = IO(new Bundle {
294307
val out = Output(Clock())
@@ -360,17 +373,21 @@ class BlackBoxSpec extends AnyFlatSpec with Matchers with ChiselSim with FileChe
360373

361374
object A extends layer.Layer(layer.LayerConfig.Extract())
362375

363-
sealed trait NoIo { this: BlackBox =>
376+
sealed trait NoIo { this: BlackBox @nowarn("cat=deprecation") =>
364377
final val io = IO(new Bundle {})
365378
}
366379

367380
// No known layers
381+
@nowarn("cat=deprecation")
368382
class Bar extends BlackBox(knownLayers = Seq.empty) with NoIo
369383
// Single known layer, built-in
384+
@nowarn("cat=deprecation")
370385
class Baz extends BlackBox(knownLayers = Seq(layers.Verification)) with NoIo
371386
// Multiple known layers
387+
@nowarn("cat=deprecation")
372388
class Qux extends BlackBox(knownLayers = Seq(layers.Verification, layers.Verification.Assert)) with NoIo
373389
// Single known layer, user-defined and should be added to the circuit
390+
@nowarn("cat=deprecation")
374391
class Quz extends BlackBox(knownLayers = Seq(A)) with NoIo
375392

376393
class Foo extends Module {
@@ -398,6 +415,7 @@ class BlackBoxSpec extends AnyFlatSpec with Matchers with ChiselSim with FileChe
398415

399416
they should "allow updates to knownLayers via adding layer-colored probe ports or via addLayer" in {
400417

418+
@nowarn("cat=deprecation")
401419
class Bar extends BlackBox {
402420
final val io = IO {
403421
new Bundle {
@@ -408,6 +426,7 @@ class BlackBoxSpec extends AnyFlatSpec with Matchers with ChiselSim with FileChe
408426

409427
object A extends layer.Layer(layer.LayerConfig.Extract())
410428

429+
@nowarn("cat=deprecation")
411430
class Baz extends BlackBox(knownLayers = Seq(A)) {
412431
final val io = IO {
413432
new Bundle {
@@ -416,6 +435,7 @@ class BlackBoxSpec extends AnyFlatSpec with Matchers with ChiselSim with FileChe
416435
}
417436
}
418437

438+
@nowarn("cat=deprecation")
419439
class Qux extends BlackBox {
420440
final val io = IO(new Bundle {})
421441
layer.addLayer(A)

src/test/scala-2/chiselTests/BlackBoxImpl.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ import org.scalacheck.Test.Failed
1313
import org.scalatest.Succeeded
1414
import org.scalatest.freespec.AnyFreeSpec
1515
import org.scalatest.matchers.should.Matchers
16+
import scala.annotation.nowarn
1617

18+
@nowarn("cat=deprecation")
1719
class BlackBoxAdd(n: Int) extends HasBlackBoxInline {
1820
val io = IO(new Bundle {
1921
val in = Input(UInt(16.W))
@@ -44,6 +46,7 @@ class UsesBlackBoxAddViaInline extends Module {
4446
io.out := blackBoxAdd.io.out
4547
}
4648

49+
@nowarn("cat=deprecation")
4750
class BlackBoxMinus extends HasBlackBoxResource {
4851
val io = IO(new Bundle {
4952
val in1 = Input(UInt(16.W))
@@ -53,6 +56,7 @@ class BlackBoxMinus extends HasBlackBoxResource {
5356
addResource("/chisel3/BlackBoxMinus.v")
5457
}
5558

59+
@nowarn("cat=deprecation")
5660
class BlackBoxMinusPath extends HasBlackBoxPath {
5761
val io = IO(new Bundle {
5862
val in1 = Input(UInt(16.W))
@@ -90,6 +94,7 @@ class UsesBlackBoxMinusViaPath extends Module {
9094
io.out := mod0.io.out
9195
}
9296

97+
@nowarn("cat=deprecation")
9398
class BlackBoxResourceNotFound extends HasBlackBoxResource {
9499
val io = IO(new Bundle {})
95100
addResource("/missing.resource")

0 commit comments

Comments
 (0)