summaryrefslogtreecommitdiff
path: root/src/test/scala/chiselTests/AnalogIntegrationSpec.scala
blob: d28c0ee15db8dbfbd54dbe0d0453e7a979e9a045 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// See LICENSE for license details.

package chiselTests

import chisel3._
import chisel3.util._
import chisel3.testers.{BasicTester, TesterDriver}
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(val 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))
}

// AnalogBlackBox wrapper, which extends Module to present the common io._ interface
class AnalogBlackBoxModule(index: Int) extends Module {
  val io = IO(new AnalogBlackBoxIO(1))
  val impl = Module(new AnalogBlackBox(index))
  io <> impl.io
}

// 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 AnalogBlackBoxModule(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 AnalogBlackBoxModule(1)),
    Module(new AnalogBlackBoxWrapper(2, Seq(2, 3))), // 2 blackboxes
    Module(new AnalogBlackBoxModule(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 AnalogBlackBoxModule(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("/chisel3/AnalogBlackBox.v"),
      TesterDriver.verilatorOnly
    )
  }
  // Use this test once Verilator supports alias
  ignore should "support arbitrary bidirectional wires" in {
    assertTesterPasses(
      new AnalogIntegrationTester(new AnalogDUT),
      Seq("/chisel3/AnalogBlackBox.v"),
      TesterDriver.verilatorOnly
    )
  }
}