From 24eecee14847fe7aa61392f7d058d7d8874fa001 Mon Sep 17 00:00:00 2001 From: Howard Mao Date: Wed, 18 Nov 2015 20:53:36 -0800 Subject: [PATCH] add DMA test --- groundtest/src/main/scala/cachetest.scala | 5 +- groundtest/src/main/scala/dmatest.scala | 123 +++++++++++++++++++++ groundtest/src/main/scala/generator.scala | 13 +-- groundtest/src/main/scala/regression.scala | 1 + groundtest/src/main/scala/tile.scala | 76 ++++++++++++- 5 files changed, 202 insertions(+), 16 deletions(-) create mode 100644 groundtest/src/main/scala/dmatest.scala diff --git a/groundtest/src/main/scala/cachetest.scala b/groundtest/src/main/scala/cachetest.scala index f943a94b..7d95ee7a 100644 --- a/groundtest/src/main/scala/cachetest.scala +++ b/groundtest/src/main/scala/cachetest.scala @@ -4,7 +4,7 @@ import Chisel._ import uncore._ import cde.{Parameters, Field} -class CacheFillTest(implicit val p: Parameters) extends GroundTest()(p) +class CacheFillTest(implicit p: Parameters) extends GroundTest()(p) with HasTileLinkParameters { val capacityKb: Int = p("L2_CAPACITY_IN_KB") val nblocks = capacityKb * 1024 / p(CacheBlockBytes) @@ -14,6 +14,8 @@ class CacheFillTest(implicit val p: Parameters) extends GroundTest()(p) val inflight = Reg(init = Bool(false)) val active = state === s_prefetch || state === s_retrieve + disablePorts(mem = false) + val (xact_id, xact_flip) = Counter(io.mem.acquire.fire(), tlMaxClientXacts) val (req_block, round_done) = Counter(io.mem.acquire.fire(), nblocks) @@ -39,5 +41,4 @@ class CacheFillTest(implicit val p: Parameters) extends GroundTest()(p) when (state === s_retrieve && round_done) { state := s_finished } io.finished := (state === s_finished) - io.cache.req.valid := Bool(false) } diff --git a/groundtest/src/main/scala/dmatest.scala b/groundtest/src/main/scala/dmatest.scala new file mode 100644 index 00000000..2bb57d4a --- /dev/null +++ b/groundtest/src/main/scala/dmatest.scala @@ -0,0 +1,123 @@ +package groundtest + +import Chisel._ +import uncore._ +import rocket._ +import junctions.PAddrBits +import cde.{Parameters, Field} + +case class DmaTestCase(source: Int, dest: Int, length: Int) + +object DmaTestCases { + def apply(cases: (Int, Int, Int) *): Seq[DmaTestCase] = { + cases.toSeq.map { + case (source, dest, length) => DmaTestCase(source, dest, length) + } + } +} + +case object DmaTestSet extends Field[Seq[DmaTestCase]] +case object DmaTestDataStart extends Field[Int] +case object DmaTestDataStride extends Field[Int] + +class DmaTest(implicit p: Parameters) extends GroundTest()(p) + with HasDmaParameters with HasCoreParameters { + + private val testSet = p(DmaTestSet) + private val dataStart = p(DmaTestDataStart) + private val dataStride = p(DmaTestDataStride) + private val wordBits = 32 + private val wordBytes = wordBits / 8 + private val pAddrBits = p(PAddrBits) + + disablePorts(cache = false, dma = false, ptw = false) + + val sourceAddrs = Vec(testSet.map(test => UInt(test.source))) + val destAddrs = Vec(testSet.map(test => UInt(test.dest))) + val transferLengths = Vec(testSet.map(test => UInt(test.length))) + val testIdx = Reg(init = UInt(0, log2Up(testSet.size))) + + val (s_start :: s_fill_req :: s_fill_resp :: s_copy_req :: s_copy_wait :: + s_check_req :: s_check_resp :: s_finished :: Nil) = Enum(Bits(), 8) + val state = Reg(init = s_start) + + val req_data = Reg(UInt(width = wordBits)) + val req_addr = Reg(UInt(width = pAddrBits)) + val bytes_left = Reg(UInt(width = pAddrBits)) + val prefetch = sourceAddrs(testIdx) === destAddrs(testIdx) + + val frontend = Module(new DmaFrontend) + frontend.io.cpu.req.valid := (state === s_copy_req) + frontend.io.cpu.req.bits := ClientDmaRequest( + cmd = Mux(prefetch, DmaRequest.DMA_CMD_PFR, DmaRequest.DMA_CMD_COPY), + src_start = sourceAddrs(testIdx), + dst_start = destAddrs(testIdx), + segment_size = transferLengths(testIdx)) + + io.dma <> frontend.io.dma + io.ptw <> frontend.io.ptw + + io.cache.req.valid := (state === s_fill_req) || (state === s_check_req) + io.cache.req.bits.addr := req_addr + io.cache.req.bits.data := req_data + io.cache.req.bits.typ := MT_W + io.cache.req.bits.cmd := Mux(state === s_fill_req, M_XWR, M_XRD) + io.cache.req.bits.kill := Bool(false) + io.cache.req.bits.phys := Bool(false) + + when (state === s_start) { + req_addr := sourceAddrs(testIdx) + req_data := UInt(dataStart) + bytes_left := transferLengths(testIdx) + state := s_fill_req + } + + when (io.cache.req.fire()) { + req_addr := req_addr + UInt(wordBytes) + bytes_left := bytes_left - UInt(wordBytes) + state := Mux(state === s_fill_req, s_fill_resp, s_check_resp) + } + + when (state === s_fill_resp && io.cache.resp.valid) { + req_data := req_data + UInt(dataStride) + state := Mux(bytes_left === UInt(0), s_copy_req, s_fill_req) + } + + when (frontend.io.cpu.req.fire()) { state := s_copy_wait } + + when (state === s_copy_wait && !frontend.io.busy) { + req_addr := destAddrs(testIdx) + req_data := UInt(dataStart) + bytes_left := transferLengths(testIdx) + state := s_check_req + } + + when (state === s_check_resp && io.cache.resp.valid) { + req_data := req_data + UInt(dataStride) + when (bytes_left > UInt(0)) { + state := s_check_req + } .elsewhen (testIdx === UInt(testSet.size - 1)) { + state := s_finished + } .otherwise { + testIdx := testIdx + UInt(1) + state := s_start + } + } + + io.finished := (state === s_finished) + + testSet.foreach { case DmaTestCase(source, dest, length) => + require(source % wordBytes == 0, "source address must be word-aligned") + require(dest % wordBytes == 0, "destination address must be word-aligned") + require(length % wordBytes == 0, "transfer length must be word-aligned") + } + + assert(!io.cache.resp.valid || !io.cache.resp.bits.has_data || + io.cache.resp.bits.data === req_data, "Received data does not match") + + val dma_timeout = Timer(1000, io.dma.req.fire(), io.dma.resp.fire()) + assert(!dma_timeout, "DMA request timed out") + + val cache_timeout = Timer(1000, io.cache.req.fire(), io.cache.resp.valid) + assert(!cache_timeout, "Memory request timed out") +} diff --git a/groundtest/src/main/scala/generator.scala b/groundtest/src/main/scala/generator.scala index 277f6546..f320b9bc 100644 --- a/groundtest/src/main/scala/generator.scala +++ b/groundtest/src/main/scala/generator.scala @@ -151,28 +151,23 @@ class HellaCacheGenerator(id: Int) s"Received incorrect data in cached generator ${id}") } -class GeneratorTest(id: Int)(implicit val p: Parameters) +class GeneratorTest(id: Int)(implicit p: Parameters) extends GroundTest()(p) with HasGeneratorParams { - val gen_finished = Wire(Vec(2, Bool())) + disablePorts(mem = !genUncached, cache = !genCached) + + val gen_finished = Wire(init = Vec.fill(2){Bool(true)}) if (genUncached) { val uncacheGen = Module(new UncachedTileLinkGenerator(id)) io.mem <> uncacheGen.io.mem gen_finished(0) := uncacheGen.io.finished - } else { - io.mem.acquire.valid := Bool(false) - io.mem.grant.ready := Bool(false) - gen_finished(0) := Bool(true) } if (genCached) { val cacheGen = Module(new HellaCacheGenerator(id)) io.cache <> cacheGen.io.mem gen_finished(1) := cacheGen.io.finished - } else { - io.cache.req.valid := Bool(false) - gen_finished(1) := Bool(true) } io.finished := gen_finished.reduce(_ && _) diff --git a/groundtest/src/main/scala/regression.scala b/groundtest/src/main/scala/regression.scala index 280bc627..8bfa1315 100644 --- a/groundtest/src/main/scala/regression.scala +++ b/groundtest/src/main/scala/regression.scala @@ -386,6 +386,7 @@ object RegressionTests { case object GroundTestRegressions extends Field[Parameters => Seq[Regression]] class RegressionTest(implicit p: Parameters) extends GroundTest()(p) { + disablePorts(mem = false, cache = false) val regressions = p(GroundTestRegressions)(p) val regressIOs = Vec(regressions.map(_.io)) diff --git a/groundtest/src/main/scala/tile.scala b/groundtest/src/main/scala/tile.scala index deabec34..06f56ef7 100644 --- a/groundtest/src/main/scala/tile.scala +++ b/groundtest/src/main/scala/tile.scala @@ -12,8 +12,7 @@ case object GroundTestMaxXacts extends Field[Int] /** A "cache" that responds to probe requests with a release indicating * the block is not present */ -class DummyCache(implicit val p: Parameters) extends Module - with HasGeneratorParams { +class DummyCache(implicit val p: Parameters) extends Module { val io = new ClientTileLinkIO val req = Reg(new Probe) @@ -37,6 +36,45 @@ class DummyCache(implicit val p: Parameters) extends Module } } +class DummyPTW(n: Int)(implicit p: Parameters) extends CoreModule()(p) { + val io = new Bundle { + val requestors = Vec(n, new TLBPTWIO).flip + } + + val req_arb = Module(new RRArbiter(new PTWReq, n)) + req_arb.io.in <> io.requestors.map(_.req) + req_arb.io.out.ready := Bool(true) + + def vpn_to_ppn(vpn: UInt): UInt = vpn(ppnBits - 1, 0) + + class QueueChannel extends ParameterizedBundle()(p) { + val ppn = UInt(width = ppnBits) + val chosen = UInt(width = log2Up(n)) + } + + val s1_ppn = vpn_to_ppn(req_arb.io.out.bits.addr) + val s2_ppn = RegEnable(s1_ppn, req_arb.io.out.valid) + val s2_chosen = RegEnable(req_arb.io.chosen, req_arb.io.out.valid) + val s2_valid = Reg(next = req_arb.io.out.valid) + + val s2_resp = Wire(new PTWResp) + s2_resp.error := Bool(false) + s2_resp.pte.ppn := s2_ppn + s2_resp.pte.reserved_for_software := UInt(0) + s2_resp.pte.d := Bool(false) + s2_resp.pte.r := Bool(false) + s2_resp.pte.typ := UInt(2) + s2_resp.pte.v := Bool(true) + + io.requestors.zipWithIndex.foreach { case (requestor, i) => + requestor.resp.valid := s2_valid && s2_chosen === UInt(i) + requestor.resp.bits := s2_resp + requestor.status.mprv := Bool(false) + requestor.status.vm := UInt("b01000") + requestor.status.prv := UInt(PRV_S) + } +} + class CSRHandler(implicit val p: Parameters) extends Module { private val csrDataBits = 64 private val csrAddrBits = 12 @@ -67,20 +105,44 @@ class CSRHandler(implicit val p: Parameters) extends Module { class GroundTestIO(implicit p: Parameters) extends ParameterizedBundle()(p) { val cache = new HellaCacheIO val mem = new ClientUncachedTileLinkIO + val dma = new DmaIO + val ptw = new TLBPTWIO val finished = Bool(OUTPUT) } -abstract class GroundTest(implicit p: Parameters) extends Module { +abstract class GroundTest(implicit val p: Parameters) extends Module { val io = new GroundTestIO + + def disablePorts(mem: Boolean = true, + cache: Boolean = true, + dma: Boolean = true, + ptw: Boolean = true) { + if (mem) { + io.mem.acquire.valid := Bool(false) + io.mem.grant.ready := Bool(false) + } + if (cache) { + io.cache.req.valid := Bool(false) + } + if (dma) { + io.dma.req.valid := Bool(false) + io.dma.resp.ready := Bool(false) + } + if (ptw) { + io.ptw.req.valid := Bool(false) + } + } } class GroundTestTile(id: Int, resetSignal: Bool) (implicit val p: Parameters) extends Tile(resetSignal)(p) { - val dcache = Module(new HellaCache()(dcacheParams)) - val dcacheIF = Module(new SimpleHellaCacheIF()(dcacheParams)) val test = p(BuildGroundTest)(id, dcacheParams) io.uncached.head <> test.io.mem + io.dma <> test.io.dma + + val dcache = Module(new HellaCache()(dcacheParams)) + val dcacheIF = Module(new SimpleHellaCacheIF()(dcacheParams)) dcacheIF.io.requestor <> test.io.cache dcache.io.cpu <> dcacheIF.io.cache io.cached.head <> dcache.io.mem @@ -88,4 +150,8 @@ class GroundTestTile(id: Int, resetSignal: Bool) val csr = Module(new CSRHandler) csr.io.finished := test.io.finished csr.io.csr <> io.host.csr + + val ptw = Module(new DummyPTW(2)) + ptw.io.requestors(0) <> test.io.ptw + ptw.io.requestors(1) <> dcache.io.ptw }