summaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
Diffstat (limited to 'src/test')
-rw-r--r--src/test/resources/AnalogBlackBox.v27
-rw-r--r--src/test/scala/chiselTests/AnalogIntegrationSpec.scala128
-rw-r--r--src/test/scala/chiselTests/AnalogSpec.scala211
3 files changed, 366 insertions, 0 deletions
diff --git a/src/test/resources/AnalogBlackBox.v b/src/test/resources/AnalogBlackBox.v
new file mode 100644
index 00000000..79e74a13
--- /dev/null
+++ b/src/test/resources/AnalogBlackBox.v
@@ -0,0 +1,27 @@
+
+module AnalogReaderBlackBox(
+ inout [31:0] bus,
+ output [31:0] out
+);
+ assign bus = 32'dz;
+ assign out = bus;
+endmodule
+
+module AnalogWriterBlackBox(
+ inout [31:0] bus,
+ input [31:0] in
+);
+ assign bus = in;
+endmodule
+
+module AnalogBlackBox #(
+ parameter index=0
+) (
+ inout [31:0] bus,
+ input port_0_in_valid,
+ input [31:0] port_0_in_bits,
+ output [31:0] port_0_out
+);
+ assign port_0_out = bus;
+ assign bus = (port_0_in_valid)? port_0_in_bits + index : 32'dZ;
+endmodule
diff --git a/src/test/scala/chiselTests/AnalogIntegrationSpec.scala b/src/test/scala/chiselTests/AnalogIntegrationSpec.scala
new file mode 100644
index 00000000..92f89e06
--- /dev/null
+++ b/src/test/scala/chiselTests/AnalogIntegrationSpec.scala
@@ -0,0 +1,128 @@
+// See LICENSE for license details.
+
+package chiselTests
+
+import chisel3._
+import chisel3.util._
+import chisel3.testers.BasicTester
+import chisel3.experimental._
+
+/* This test is different from AnalogSpec in that it uses more complicated black boxes that can each
+ * drive the bidirectional bus. It was created to evaluate Analog with synthesis tools since the
+ * simple tests in AnalogSpec don't anything interesting in them to synthesize.
+ */
+
+class AnalogBlackBoxPort extends Bundle {
+ val in = Input(Valid(UInt(32.W)))
+ val out = Output(UInt(32.W))
+}
+
+// This IO can be used for a single BlackBox or to group multiple
+// Has multiple ports for driving and checking but only one shared bus
+class AnalogBlackBoxIO(n: Int) extends Bundle {
+ require(n > 0)
+ val bus = Analog(32.W)
+ val port = Vec(n, new AnalogBlackBoxPort)
+}
+
+// Assigns bus to out
+// Assigns in.bits + index to bus when in.valid
+class AnalogBlackBox(index: Int) extends BlackBox(Map("index" -> index)) {
+ val io = IO(new AnalogBlackBoxIO(1))
+}
+
+// Wraps up n blackboxes, connecing their buses and simply forwarding their ports up
+class AnalogBlackBoxWrapper(n: Int, idxs: Seq[Int]) extends Module {
+ require(n > 0)
+ val io = IO(new AnalogBlackBoxIO(n))
+ val bbs = idxs.map(i => Module(new AnalogBlackBox(i)))
+ io.bus <> bbs.head.io.bus // Always bulk connect io.bus to first bus
+ io.port <> bbs.flatMap(_.io.port) // Connect ports
+ attach(bbs.map(_.io.bus):_*) // Attach all the buses
+}
+
+// Common superclass for AnalogDUT and AnalogSmallDUT
+abstract class AnalogDUTModule(numBlackBoxes: Int) extends Module {
+ require(numBlackBoxes > 0)
+ val io = IO(new Bundle {
+ val ports = Vec(numBlackBoxes, new AnalogBlackBoxPort)
+ })
+}
+
+/** Single test case for lots of things
+ *
+ * $ - Wire at top connecting child inouts (Done in AnalogDUT)
+ * $ - Port inout connected to 1 or more children inouts (AnalogBackBoxWrapper)
+ * $ - Multiple port inouts connected (AnalogConnector)
+ */
+class AnalogDUT extends AnalogDUTModule(5) { // 5 BlackBoxes
+ val mods = Seq(
+ Module(new AnalogBlackBoxWrapper(1, Seq(0))),
+ Module(new AnalogBlackBox(1)),
+ Module(new AnalogBlackBoxWrapper(2, Seq(2, 3))), // 2 blackboxes
+ Module(new AnalogBlackBox(4))
+ )
+ // Connect all ports to top
+ io.ports <> mods.flatMap(_.io.port)
+ // Attach first 3 Modules
+ attach(mods.take(3).map(_.io.bus):_*)
+ // Attach last module to 1st through AnalogConnector
+ val con = Module(new AnalogConnector)
+ attach(con.io.bus1, mods.head.io.bus)
+ attach(con.io.bus2, mods.last.io.bus)
+}
+
+/** Same as [[AnalogDUT]] except it omits [[AnalogConnector]] because that is currently not
+ * supported by Verilator
+ * @todo Delete once Verilator can handle [[AnalogDUT]]
+ */
+class AnalogSmallDUT extends AnalogDUTModule(4) { // 4 BlackBoxes
+ val mods = Seq(
+ Module(new AnalogBlackBoxWrapper(1, Seq(0))),
+ Module(new AnalogBlackBox(1)),
+ Module(new AnalogBlackBoxWrapper(2, Seq(2, 3))) // 2 BlackBoxes
+ )
+ // Connect all ports to top
+ io.ports <> mods.flatMap(_.io.port)
+ // Attach first 3 Modules
+ attach(mods.take(3).map(_.io.bus):_*)
+}
+
+
+// This tester is primarily intended to be able to pass the dut to synthesis
+class AnalogIntegrationTester(mod: => AnalogDUTModule) extends BasicTester {
+ val BusValue = 2.U(32.W) // arbitrary
+
+ val dut = Module(mod)
+
+ val expectedValue = Wire(UInt(32.W))
+ expectedValue := BusValue // Overridden each cycle
+
+ val (cycle, done) = Counter(true.B, dut.io.ports.size)
+ for ((dut, idx) <- dut.io.ports.zipWithIndex) {
+ printf(p"@$cycle: BlackBox #$idx: $dut\n")
+ // Defaults
+ dut.in.valid := false.B
+ dut.in.bits := BusValue
+ // Error checking
+ assert(dut.out === expectedValue)
+
+ when (cycle === idx.U) {
+ expectedValue := BusValue + idx.U
+ dut.in.valid := true.B
+
+ }
+ }
+ when (done) { stop() }
+}
+
+class AnalogIntegrationSpec extends ChiselFlatSpec {
+ behavior of "Verilator"
+ it should "support simple bidirectional wires" in {
+ assertTesterPasses(new AnalogIntegrationTester(new AnalogSmallDUT), Seq("/AnalogBlackBox.v"))
+ }
+ // Use this test once Verilator supports alias
+ ignore should "support arbitrary bidirectional wires" in {
+ assertTesterPasses(new AnalogIntegrationTester(new AnalogDUT), Seq("/AnalogBlackBox.v"))
+ }
+}
diff --git a/src/test/scala/chiselTests/AnalogSpec.scala b/src/test/scala/chiselTests/AnalogSpec.scala
new file mode 100644
index 00000000..576a5a1f
--- /dev/null
+++ b/src/test/scala/chiselTests/AnalogSpec.scala
@@ -0,0 +1,211 @@
+// See LICENSE for license details.
+
+package chiselTests
+
+import chisel3._
+import chisel3.util._
+import chisel3.testers.BasicTester
+import chisel3.experimental.{Analog, attach}
+
+// IO for Modules that just connect bus to out
+class AnalogReaderIO extends Bundle {
+ val bus = Analog(32.W)
+ val out = Output(UInt(32.W))
+}
+// IO for Modules that drive bus from in (there should be only 1)
+class AnalogWriterIO extends Bundle {
+ val bus = Analog(32.W)
+ val in = Input(UInt(32.W))
+}
+
+trait AnalogReader {
+ self: Module =>
+ final val io = self.IO(new AnalogReaderIO)
+}
+
+class AnalogReaderBlackBox extends BlackBox with AnalogReader
+
+class AnalogReaderWrapper extends Module with AnalogReader {
+ val mod = Module(new AnalogReaderBlackBox)
+ io <> mod.io
+}
+class AnalogWriterBlackBox extends BlackBox {
+ val io = IO(new AnalogWriterIO)
+}
+// Connects two Analog ports
+class AnalogConnector extends Module {
+ val io = IO(new Bundle {
+ val bus1 = Analog(32.W)
+ val bus2 = Analog(32.W)
+ })
+ io.bus1 <> io.bus2
+}
+
+// Parent class for tests connecing up AnalogReaders and AnalogWriters
+abstract class AnalogTester extends BasicTester {
+ final val BusValue = "hdeadbeef".U
+
+ final val (cycle, done) = Counter(true.B, 2)
+ when (done) { stop() }
+
+ final val writer = Module(new AnalogWriterBlackBox)
+ writer.io.in := BusValue
+
+ final def check(reader: Module with AnalogReader): Unit =
+ assert(reader.io.out === BusValue)
+}
+
+class AnalogSpec extends ChiselFlatSpec {
+ behavior of "Analog"
+
+ it should "NOT be bindable to registers" in {
+ a [ChiselException] should be thrownBy {
+ elaborate { new Module {
+ val io = IO(new Bundle {})
+ val reg = Reg(Analog(32.W))
+ }}
+ }
+ }
+
+ it should "NOT be bindable to a direction" in {
+ a [ChiselException] should be thrownBy {
+ elaborate { new Module {
+ val io = IO(new Bundle {
+ val a = Input(Analog(32.W))
+ })
+ }}
+ }
+ a [ChiselException] should be thrownBy {
+ elaborate { new Module {
+ val io = IO(new Bundle {
+ val a = Output(Analog(32.W))
+ })
+ }}
+ }
+ }
+
+ it should "be flippable" in {
+ elaborate { new Module {
+ val io = IO(new Bundle {
+ val a = Flipped(Analog(32.W))
+ })
+ }}
+ }
+
+ // There is no binding on the type of a memory
+ // Should this be an error?
+ ignore should "NOT be a legal type for Mem" in {
+ a [ChiselException] should be thrownBy {
+ elaborate { new Module {
+ val io = IO(new Bundle {})
+ val mem = Mem(16, Analog(32.W))
+ }}
+ }
+ }
+
+ it should "NOT be bindable to Mem ports" in {
+ a [ChiselException] should be thrownBy {
+ elaborate { new Module {
+ val io = IO(new Bundle {})
+ val mem = Mem(16, Analog(32.W))
+ val port = mem(5.U)
+ }}
+ }
+ }
+
+ // TODO This should probably be caught in Chisel
+ // Also note this relies on executing Firrtl from Chisel directly
+ it should "NOT be connectable to UInts" in {
+ a [Exception] should be thrownBy {
+ runTester { new BasicTester {
+ val uint = Wire(init = 0.U(32.W))
+ val sint = Wire(Analog(32.W))
+ sint := uint
+ }}
+ }
+ }
+
+ it should "work with 2 blackboxes bulk connected" in {
+ assertTesterPasses(new AnalogTester {
+ val mod = Module(new AnalogReaderBlackBox)
+ mod.io.bus <> writer.io.bus
+ check(mod)
+ }, Seq("/AnalogBlackBox.v"))
+ }
+
+ it should "error if any bulk connected more than once" in {
+ a [ChiselException] should be thrownBy {
+ elaborate(new Module {
+ val io = IO(new Bundle {})
+ val wires = List.fill(3)(Wire(Analog(32.W)))
+ wires(0) <> wires(1)
+ wires(0) <> wires(2)
+ })
+ }
+ }
+
+ it should "work with 3 blackboxes attached" in {
+ assertTesterPasses(new AnalogTester {
+ val mods = Seq.fill(2)(Module(new AnalogReaderBlackBox))
+ attach(writer.io.bus, mods(0).io.bus, mods(1).io.bus)
+ mods.foreach(check(_))
+ }, Seq("/AnalogBlackBox.v"))
+ }
+
+ it should "work with 3 blackboxes separately attached via a wire" in {
+ assertTesterPasses(new AnalogTester {
+ val mods = Seq.fill(2)(Module(new AnalogReaderBlackBox))
+ val busWire = Wire(Analog(32.W))
+ attach(busWire, writer.io.bus)
+ attach(busWire, mods(0).io.bus)
+ attach(mods(1).io.bus, busWire)
+ mods.foreach(check(_))
+ }, Seq("/AnalogBlackBox.v"))
+ }
+
+ // This does not currently work in Verilator unless Firrtl does constant prop and dead code
+ // elimination on these wires
+ ignore should "work with intermediate wires attached to each other" in {
+ assertTesterPasses(new AnalogTester {
+ val mod = Module(new AnalogReaderBlackBox)
+ val busWire = Seq.fill(2)(Wire(Analog(32.W)))
+ attach(busWire(0), writer.io.bus)
+ attach(busWire(1), mod.io.bus)
+ attach(busWire(0), busWire(1))
+ check(mod)
+ }, Seq("/AnalogBlackBox.v"))
+ }
+
+ it should "work with blackboxes at different levels of the module hierarchy" in {
+ assertTesterPasses(new AnalogTester {
+ val mods = Seq(Module(new AnalogReaderBlackBox), Module(new AnalogReaderWrapper))
+ val busWire = Wire(writer.io.bus)
+ attach(writer.io.bus, mods(0).io.bus, mods(1).io.bus)
+ mods.foreach(check(_))
+ }, Seq("/AnalogBlackBox.v"))
+ }
+
+ // This does not currently work in Verilator, but does work in VCS
+ ignore should "support two analog ports in the same module" in {
+ assertTesterPasses(new AnalogTester {
+ val reader = Module(new AnalogReaderBlackBox)
+ val connector = Module(new AnalogConnector)
+ connector.io.bus1 <> writer.io.bus
+ reader.io.bus <> connector.io.bus2
+ check(reader)
+ }, Seq("/AnalogBlackBox.v"))
+ }
+
+ it should "NOT support conditional connection of analog types" in {
+ a [ChiselException] should be thrownBy {
+ assertTesterPasses(new AnalogTester {
+ val mod = Module(new AnalogReaderBlackBox)
+ when (cycle > 3.U) {
+ mod.io.bus <> writer.io.bus
+ }
+ check(mod)
+ }, Seq("/AnalogBlackBox.v"))
+ }
+ }
+}
+