1
0
rocket-chip/src/main/scala/rocketchip/TestHarness.scala
2016-10-31 11:42:47 -07:00

175 lines
5.0 KiB
Scala

// See LICENSE for license details.
package rocketchip
import Chisel._
import cde.{Parameters, Field}
import junctions._
import junctions.NastiConstants._
import util.LatencyPipe
case object BuildExampleTop extends Field[Parameters => ExampleTop[coreplex.BaseCoreplex]]
case object SimMemLatency extends Field[Int]
class TestHarness(q: Parameters) extends Module {
val io = new Bundle {
val success = Bool(OUTPUT)
}
val dut = Module(q(BuildExampleTop)(q).module)
implicit val p = dut.p
// This test harness isn't especially flexible yet
require(dut.io.mem_clk.isEmpty)
require(dut.io.mem_rst.isEmpty)
require(dut.io.mem_ahb.isEmpty)
require(dut.io.mem_tl.isEmpty)
require(dut.io.bus_clk.isEmpty)
require(dut.io.bus_rst.isEmpty)
for (int <- dut.io.interrupts(0))
int := Bool(false)
if (dut.io.mem_axi.nonEmpty) {
val memSize = p(ExtMemSize)
require(memSize % dut.io.mem_axi.size == 0)
for (axi <- dut.io.mem_axi) {
val mem = Module(new SimAXIMem(memSize / dut.io.mem_axi.size))
mem.io.axi.ar <> axi.ar
mem.io.axi.aw <> axi.aw
mem.io.axi.w <> axi.w
axi.r <> LatencyPipe(mem.io.axi.r, p(SimMemLatency))
axi.b <> LatencyPipe(mem.io.axi.b, p(SimMemLatency))
}
}
if (!p(IncludeJtagDTM)) {
// Todo: enable the usage of different clocks
// to test the synchronizer more aggressively.
val dtm_clock = clock
val dtm_reset = reset
if (dut.io.debug_clk.isDefined) dut.io.debug_clk.get := dtm_clock
if (dut.io.debug_rst.isDefined) dut.io.debug_rst.get := dtm_reset
val dtm = Module(new SimDTM).connect(dtm_clock, dtm_reset, dut.io.debug.get,
dut.io.success, io.success)
} else {
val jtag = Module(new JTAGVPI).connect(dut.io.jtag.get, reset, io.success)
}
for (bus_axi <- dut.io.bus_axi) {
bus_axi.ar.valid := Bool(false)
bus_axi.aw.valid := Bool(false)
bus_axi.w.valid := Bool(false)
bus_axi.r.ready := Bool(false)
bus_axi.b.ready := Bool(false)
}
for (mmio_axi <- dut.io.mmio_axi) {
val slave = Module(new NastiErrorSlave)
slave.io <> mmio_axi
}
}
class SimAXIMem(size: BigInt)(implicit p: Parameters) extends NastiModule()(p) {
val io = new Bundle {
val axi = new NastiIO().flip
}
val rValid = Reg(init = Bool(false))
val ar = RegEnable(io.axi.ar.bits, io.axi.ar.fire())
io.axi.ar.ready := !rValid
when (io.axi.ar.fire()) { rValid := Bool(true) }
when (io.axi.r.fire()) {
assert(ar.burst === NastiConstants.BURST_INCR)
ar.addr := ar.addr + (UInt(1) << ar.size)
ar.len := ar.len - UInt(1)
when (ar.len === UInt(0)) { rValid := Bool(false) }
}
val w = io.axi.w.bits
require((size * 8) % nastiXDataBits == 0)
val depth = (size * 8) / nastiXDataBits
val mem = Mem(depth.toInt, w.data)
val wValid = Reg(init = Bool(false))
val bValid = Reg(init = Bool(false))
val aw = RegEnable(io.axi.aw.bits, io.axi.aw.fire())
io.axi.aw.ready := !wValid && !bValid
io.axi.w.ready := wValid
when (io.axi.b.fire()) { bValid := Bool(false) }
when (io.axi.aw.fire()) { wValid := Bool(true) }
when (io.axi.w.fire()) {
assert(aw.burst === NastiConstants.BURST_INCR)
aw.addr := aw.addr + (UInt(1) << aw.size)
aw.len := aw.len - UInt(1)
when (aw.len === UInt(0)) {
wValid := Bool(false)
bValid := Bool(true)
}
def row = mem((aw.addr >> log2Ceil(nastiXDataBits/8))(log2Ceil(depth)-1, 0))
val mask = FillInterleaved(8, w.strb)
val newData = mask & w.data | ~mask & row
row := newData
}
io.axi.b.valid := bValid
io.axi.b.bits.id := aw.id
io.axi.b.bits.resp := RESP_OKAY
io.axi.r.valid := rValid
io.axi.r.bits.id := ar.id
io.axi.r.bits.data := mem((ar.addr >> log2Ceil(nastiXDataBits/8))(log2Ceil(depth)-1, 0))
io.axi.r.bits.resp := RESP_OKAY
io.axi.r.bits.last := ar.len === UInt(0)
}
class SimDTM(implicit p: Parameters) extends BlackBox {
val io = new Bundle {
val clk = Clock(INPUT)
val reset = Bool(INPUT)
val debug = new uncore.devices.DebugBusIO
val exit = UInt(OUTPUT, 32)
}
def connect(tbclk: Clock, tbreset: Bool, dutio: uncore.devices.DebugBusIO,
dutsuccess: Bool, tbsuccess: Bool) = {
io.clk := tbclk
io.reset := tbreset
dutio <> io.debug
tbsuccess := dutsuccess || io.exit === UInt(1)
when (io.exit >= UInt(2)) {
printf("*** FAILED *** (exit code = %d)\n", io.exit >> UInt(1))
stop(1)
}
}
}
class JTAGVPI(implicit val p: Parameters) extends BlackBox {
val io = new Bundle {
val jtag = new JTAGIO(false)
val enable = Bool(INPUT)
val init_done = Bool(INPUT)
}
def connect(dutio: JTAGIO, tbreset: Bool, tbsuccess: Bool) = {
dutio <> io.jtag
// To be proper,
// TRST should really be synchronized
// with TCK. But this is a fairly
// accurate representation of how
// HW may drive this signal.
// Neither OpenOCD nor JtagVPI drive TRST.
dutio.TRST := tbreset
io.enable := ~tbreset
io.init_done := ~tbreset
// Success is determined by the gdbserver
// which is controlling this simulation.
tbsuccess := Bool(false)
}
}