summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJack2022-04-26 02:53:08 +0000
committerJack2022-04-26 02:53:08 +0000
commit3a6cc75d72cbf890bbd45a002c31d16abfc6896d (patch)
tree298a39cbdbcd7e89953d75dbd840884f29ff7699 /src
parentbe1ac06bf20c6c3d84c8ce5b0a50e2980e546e7e (diff)
parentd5a964f6e7beea1f38f9623224fc65e2397e1fe7 (diff)
Merge branch '3.5.x' into 3.5-release
Diffstat (limited to 'src')
-rw-r--r--src/main/scala/chisel3/util/BlackBoxUtils.scala8
-rw-r--r--src/main/scala/chisel3/util/ExtModuleUtils.scala8
-rw-r--r--src/test/scala/chiselTests/BlackBox.scala29
-rw-r--r--src/test/scala/chiselTests/BulkConnectSpec.scala20
-rw-r--r--src/test/scala/chiselTests/InvalidateAPISpec.scala8
-rw-r--r--src/test/scala/chiselTests/Mem.scala52
-rw-r--r--src/test/scala/chiselTests/ReduceTreeSpec.scala106
-rw-r--r--src/test/scala/chiselTests/experimental/DataView.scala30
-rw-r--r--src/test/scala/chiselTests/experimental/DataViewTargetSpec.scala4
-rw-r--r--src/test/scala/chiselTests/experimental/FlatIOSpec.scala51
10 files changed, 298 insertions, 18 deletions
diff --git a/src/main/scala/chisel3/util/BlackBoxUtils.scala b/src/main/scala/chisel3/util/BlackBoxUtils.scala
index 7c4400f8..579a6307 100644
--- a/src/main/scala/chisel3/util/BlackBoxUtils.scala
+++ b/src/main/scala/chisel3/util/BlackBoxUtils.scala
@@ -4,13 +4,7 @@ package chisel3.util
import chisel3._
import chisel3.experimental.{ChiselAnnotation, RunFirrtlTransform}
-import firrtl.transforms.{
- BlackBoxInlineAnno,
- BlackBoxNotFoundException,
- BlackBoxPathAnno,
- BlackBoxResourceAnno,
- BlackBoxSourceHelper
-}
+import firrtl.transforms.{BlackBoxInlineAnno, BlackBoxNotFoundException, BlackBoxPathAnno, BlackBoxSourceHelper}
import firrtl.annotations.ModuleName
import logger.LazyLogging
diff --git a/src/main/scala/chisel3/util/ExtModuleUtils.scala b/src/main/scala/chisel3/util/ExtModuleUtils.scala
index 5c9c02ba..8a687d36 100644
--- a/src/main/scala/chisel3/util/ExtModuleUtils.scala
+++ b/src/main/scala/chisel3/util/ExtModuleUtils.scala
@@ -3,13 +3,7 @@
package chisel3.util
import chisel3.experimental.{ChiselAnnotation, ExtModule, RunFirrtlTransform}
-import firrtl.transforms.{
- BlackBoxInlineAnno,
- BlackBoxNotFoundException,
- BlackBoxPathAnno,
- BlackBoxResourceAnno,
- BlackBoxSourceHelper
-}
+import firrtl.transforms.{BlackBoxInlineAnno, BlackBoxNotFoundException, BlackBoxPathAnno, BlackBoxSourceHelper}
import BlackBoxHelpers._
diff --git a/src/test/scala/chiselTests/BlackBox.scala b/src/test/scala/chiselTests/BlackBox.scala
index 27cdbbc4..f923a94a 100644
--- a/src/test/scala/chiselTests/BlackBox.scala
+++ b/src/test/scala/chiselTests/BlackBox.scala
@@ -145,6 +145,17 @@ class BlackBoxTypeParam(w: Int, raw: String) extends BlackBox(Map("T" -> RawPara
})
}
+class BlackBoxNoIO extends BlackBox {
+ // Whoops! typo
+ val ioo = IO(new Bundle {
+ val out = Output(UInt(8.W))
+ })
+}
+
+class BlackBoxUIntIO extends BlackBox {
+ val io = IO(Output(UInt(8.W)))
+}
+
class BlackBoxWithParamsTester extends BasicTester {
val blackBoxOne = Module(new BlackBoxConstant(1))
val blackBoxFour = Module(new BlackBoxConstant(4))
@@ -192,7 +203,23 @@ class BlackBoxSpec extends ChiselFlatSpec {
assert(DataMirror.modulePorts(m) == Seq("in" -> m.io.in, "out" -> m.io.out))
})
}
- "A BlackBoxed using suggestName(\"io\")" should "work (but don't do this)" in {
+ "A BlackBox using suggestName(\"io\")" should "work (but don't do this)" in {
assertTesterPasses({ new BlackBoxTesterSuggestName }, Seq("/chisel3/BlackBoxTest.v"), TesterDriver.verilatorOnly)
}
+
+ "A BlackBox with no 'val io'" should "give a reasonable error message" in {
+ (the[ChiselException] thrownBy {
+ ChiselStage.elaborate(new Module {
+ val inst = Module(new BlackBoxNoIO)
+ })
+ }).getMessage should include("must have a port named 'io' of type Record")
+ }
+
+ "A BlackBox with non-Record 'val io'" should "give a reasonable error message" in {
+ (the[ChiselException] thrownBy {
+ ChiselStage.elaborate(new Module {
+ val inst = Module(new BlackBoxUIntIO)
+ })
+ }).getMessage should include("must have a port named 'io' of type Record")
+ }
}
diff --git a/src/test/scala/chiselTests/BulkConnectSpec.scala b/src/test/scala/chiselTests/BulkConnectSpec.scala
index 463122bd..281890d4 100644
--- a/src/test/scala/chiselTests/BulkConnectSpec.scala
+++ b/src/test/scala/chiselTests/BulkConnectSpec.scala
@@ -94,6 +94,26 @@ class BulkConnectSpec extends ChiselPropSpec {
chirrtl should include("deq <= enq")
}
+ property("Chisel connects should not emit a FIRRTL bulk connect for BlackBox IO Bundles") {
+ class MyBundle extends Bundle {
+ val O: Bool = Output(Bool())
+ val I: Bool = Input(Bool())
+ }
+
+ val chirrtl = ChiselStage.emitChirrtl(new Module {
+ val io: MyBundle = IO(Flipped(new MyBundle))
+
+ val bb = Module(new BlackBox {
+ val io: MyBundle = IO(Flipped(new MyBundle))
+ })
+
+ io <> bb.io
+ })
+ // There won't be a bb.io Bundle in FIRRTL, so connections have to be done element-wise
+ chirrtl should include("bb.O <= io.O")
+ chirrtl should include("io.I <= bb.I")
+ }
+
property("MonoConnect should bulk connect undirectioned internal wires") {
val chirrtl = ChiselStage.emitChirrtl(new Module {
val io = IO(new Bundle {})
diff --git a/src/test/scala/chiselTests/InvalidateAPISpec.scala b/src/test/scala/chiselTests/InvalidateAPISpec.scala
index 2c51e5d2..dbd353a0 100644
--- a/src/test/scala/chiselTests/InvalidateAPISpec.scala
+++ b/src/test/scala/chiselTests/InvalidateAPISpec.scala
@@ -228,4 +228,12 @@ class InvalidateAPISpec extends ChiselPropSpec with Matchers with BackendCompila
val firrtlOutput = myGenerateFirrtl(new ModuleWithoutDontCare)
firrtlOutput should include("is invalid")
}
+
+ property("a clock should be able to be connected to a DontCare") {
+ class ClockConnectedToDontCare extends Module {
+ val foo = IO(Output(Clock()))
+ foo := DontCare
+ }
+ myGenerateFirrtl(new ClockConnectedToDontCare) should include("foo is invalid")
+ }
}
diff --git a/src/test/scala/chiselTests/Mem.scala b/src/test/scala/chiselTests/Mem.scala
index 4dcb1ad4..c5fcc6b1 100644
--- a/src/test/scala/chiselTests/Mem.scala
+++ b/src/test/scala/chiselTests/Mem.scala
@@ -3,6 +3,7 @@
package chiselTests
import chisel3._
+import chisel3.stage.ChiselStage
import chisel3.util._
import chisel3.testers.BasicTester
@@ -141,6 +142,52 @@ class MemBundleTester extends BasicTester {
}
}
+private class TrueDualPortMemoryIO(val addrW: Int, val dataW: Int) extends Bundle {
+ require(addrW > 0, "address width must be greater than 0")
+ require(dataW > 0, "data width must be greater than 0")
+
+ val clka = Input(Clock())
+ val ena = Input(Bool())
+ val wea = Input(Bool())
+ val addra = Input(UInt(addrW.W))
+ val dia = Input(UInt(dataW.W))
+ val doa = Output(UInt(dataW.W))
+
+ val clkb = Input(Clock())
+ val enb = Input(Bool())
+ val web = Input(Bool())
+ val addrb = Input(UInt(addrW.W))
+ val dib = Input(UInt(dataW.W))
+ val dob = Output(UInt(dataW.W))
+}
+
+private class TrueDualPortMemory(addrW: Int, dataW: Int) extends RawModule {
+ val io = IO(new TrueDualPortMemoryIO(addrW, dataW))
+ val ram = SyncReadMem(1 << addrW, UInt(dataW.W))
+
+ // Port a
+ withClock(io.clka) {
+ io.doa := DontCare
+ when(io.ena) {
+ when(io.wea) {
+ ram(io.addra) := io.dia
+ }
+ io.doa := ram(io.addra)
+ }
+ }
+
+ // Port b
+ withClock(io.clkb) {
+ io.dob := DontCare
+ when(io.enb) {
+ when(io.web) {
+ ram(io.addrb) := io.dib
+ }
+ io.dob := ram(io.addrb)
+ }
+ }
+}
+
class MemorySpec extends ChiselPropSpec {
property("Mem of Vec should work") {
assertTesterPasses { new MemVecTester }
@@ -186,4 +233,9 @@ class MemorySpec extends ChiselPropSpec {
|}
|""".stripMargin should compile
}
+
+ property("memories in modules without implicit clock should compile without warning or error") {
+ val stage = new ChiselStage
+ stage.emitVerilog(new TrueDualPortMemory(4, 32))
+ }
}
diff --git a/src/test/scala/chiselTests/ReduceTreeSpec.scala b/src/test/scala/chiselTests/ReduceTreeSpec.scala
new file mode 100644
index 00000000..3f078106
--- /dev/null
+++ b/src/test/scala/chiselTests/ReduceTreeSpec.scala
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: Apache-2.0
+
+package chiselTests
+
+import chisel3._
+import chisel3.util._
+import chisel3.testers.BasicTester
+
+class Arbiter[T <: Data: Manifest](n: Int, private val gen: T) extends Module {
+ val io = IO(new Bundle {
+ val in = Flipped(Vec(n, new DecoupledIO(gen)))
+ val out = new DecoupledIO(gen)
+ })
+
+ def arbitrateTwo(a: DecoupledIO[T], b: DecoupledIO[T]) = {
+
+ val idleA :: idleB :: hasA :: hasB :: Nil = Enum(4)
+ val regData = Reg(gen)
+ val regState = RegInit(idleA)
+ val out = Wire(new DecoupledIO(gen))
+
+ a.ready := regState === idleA
+ b.ready := regState === idleB
+ out.valid := (regState === hasA || regState === hasB)
+
+ switch(regState) {
+ is(idleA) {
+ when(a.valid) {
+ regData := a.bits
+ regState := hasA
+ }.otherwise {
+ regState := idleB
+ }
+ }
+ is(idleB) {
+ when(b.valid) {
+ regData := b.bits
+ regState := hasB
+ }.otherwise {
+ regState := idleA
+ }
+ }
+ is(hasA) {
+ when(out.ready) {
+ regState := idleB
+ }
+ }
+ is(hasB) {
+ when(out.ready) {
+ regState := idleA
+ }
+ }
+ }
+
+ out.bits := regData.asUInt + 1.U
+ out
+ }
+
+ io.out <> io.in.reduceTree(arbitrateTwo)
+}
+
+class ReduceTreeBalancedTester(nodes: Int) extends BasicTester {
+
+ val cnt = RegInit(0.U(8.W))
+ val min = RegInit(99.U(8.W))
+ val max = RegInit(0.U(8.W))
+
+ val dut = Module(new Arbiter(nodes, UInt(16.W)))
+ for (i <- 0 until nodes) {
+ dut.io.in(i).valid := true.B
+ dut.io.in(i).bits := 0.U
+ }
+ dut.io.out.ready := true.B
+
+ when(dut.io.out.valid) {
+ val hops = dut.io.out.bits
+ when(hops < min) {
+ min := hops
+ }
+ when(hops > max) {
+ max := hops
+ }
+ }
+
+ when(!(max === 0.U || min === 99.U)) {
+ assert(max - min <= 1.U)
+ }
+
+ cnt := cnt + 1.U
+ when(cnt === 10.U) {
+ stop()
+ }
+}
+
+class ReduceTreeBalancedSpec extends ChiselPropSpec {
+ property("Tree shall be fair and shall have a maximum difference of one hop for each node") {
+
+ // This test will fail for 5 nodes due to an unbalanced tree.
+ // A fix is on the way.
+ for (n <- 1 to 5) {
+ assertTesterPasses {
+ new ReduceTreeBalancedTester(n)
+ }
+ }
+ }
+}
diff --git a/src/test/scala/chiselTests/experimental/DataView.scala b/src/test/scala/chiselTests/experimental/DataView.scala
index 0285a524..e7caacfd 100644
--- a/src/test/scala/chiselTests/experimental/DataView.scala
+++ b/src/test/scala/chiselTests/experimental/DataView.scala
@@ -332,6 +332,36 @@ class DataViewSpec extends ChiselFlatSpec {
chirrtl should include("dataOut <= vec[addr]")
}
+ it should "support dynamic indexing for Vecs that correspond 1:1 in a view" in {
+ class MyBundle extends Bundle {
+ val foo = Vec(4, UInt(8.W))
+ val bar = UInt(2.W)
+ }
+ implicit val myView = DataView[(Vec[UInt], UInt), MyBundle](
+ _ => new MyBundle,
+ _._1 -> _.foo,
+ _._2 -> _.bar
+ )
+ class MyModule extends Module {
+ val dataIn = IO(Input(UInt(8.W)))
+ val addr = IO(Input(UInt(2.W)))
+ val dataOut = IO(Output(UInt(8.W)))
+
+ val vec = RegInit(0.U.asTypeOf(Vec(4, UInt(8.W))))
+ val addrReg = Reg(UInt(2.W))
+ val view = (vec, addrReg).viewAs[MyBundle]
+ // Dynamic indexing is more of a "generator" in Chisel3 than an individual node
+ // This style is not recommended, this is just testing the behavior
+ val selected = view.foo(view.bar)
+ view.bar := addr
+ selected := dataIn
+ dataOut := selected
+ }
+ val chirrtl = ChiselStage.emitChirrtl(new MyModule)
+ chirrtl should include("vec[addrReg] <= dataIn")
+ chirrtl should include("dataOut <= vec[addrReg]")
+ }
+
it should "error if you try to dynamically index a Vec view that does not correspond to a Vec target" in {
class MyModule extends Module {
val inA, inB = IO(Input(UInt(8.W)))
diff --git a/src/test/scala/chiselTests/experimental/DataViewTargetSpec.scala b/src/test/scala/chiselTests/experimental/DataViewTargetSpec.scala
index da27c9c8..ddeeab6e 100644
--- a/src/test/scala/chiselTests/experimental/DataViewTargetSpec.scala
+++ b/src/test/scala/chiselTests/experimental/DataViewTargetSpec.scala
@@ -125,9 +125,7 @@ class DataViewTargetSpec extends ChiselFlatSpec {
val pairs = annos.collect { case DummyAnno(t, idx) => (idx, t.toString) }.sortBy(_._1)
val expected = Seq(
0 -> "~MyParent|MyChild>out.foo",
- // The child of the view that was itself an Aggregate got split because 1:1 is lacking here
- 1 -> "~MyParent|MyChild>out.foo[0]",
- 1 -> "~MyParent|MyChild>out.foo[1]",
+ 1 -> "~MyParent|MyChild>out.foo",
2 -> "~MyParent|MyParent/inst:MyChild>out.foo",
3 -> "~MyParent|MyParent/inst:MyChild>out"
)
diff --git a/src/test/scala/chiselTests/experimental/FlatIOSpec.scala b/src/test/scala/chiselTests/experimental/FlatIOSpec.scala
new file mode 100644
index 00000000..dfce447f
--- /dev/null
+++ b/src/test/scala/chiselTests/experimental/FlatIOSpec.scala
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: Apache-2.0
+
+package chiselTests.experimental
+
+import chisel3._
+import chisel3.util.Valid
+import chisel3.stage.ChiselStage.emitChirrtl
+import chisel3.experimental.FlatIO
+import chiselTests.ChiselFlatSpec
+
+class FlatIOSpec extends ChiselFlatSpec {
+ behavior.of("FlatIO")
+
+ it should "create ports without a prefix" in {
+ class MyModule extends RawModule {
+ val io = FlatIO(new Bundle {
+ val in = Input(UInt(8.W))
+ val out = Output(UInt(8.W))
+ })
+ io.out := io.in
+ }
+ val chirrtl = emitChirrtl(new MyModule)
+ chirrtl should include("input in : UInt<8>")
+ chirrtl should include("output out : UInt<8>")
+ chirrtl should include("out <= in")
+ }
+
+ it should "support bulk connections between FlatIOs and regular IOs" in {
+ class MyModule extends RawModule {
+ val in = FlatIO(Input(Valid(UInt(8.W))))
+ val out = IO(Output(Valid(UInt(8.W))))
+ out := in
+ }
+ val chirrtl = emitChirrtl(new MyModule)
+ chirrtl should include("out.bits <= bits")
+ chirrtl should include("out.valid <= valid")
+ }
+
+ it should "dynamically indexing Vecs inside of FlatIOs" in {
+ class MyModule extends RawModule {
+ val io = FlatIO(new Bundle {
+ val addr = Input(UInt(2.W))
+ val in = Input(Vec(4, UInt(8.W)))
+ val out = Output(Vec(4, UInt(8.W)))
+ })
+ io.out(io.addr) := io.in(io.addr)
+ }
+ val chirrtl = emitChirrtl(new MyModule)
+ chirrtl should include("out[addr] <= in[addr]")
+ }
+}