diff --git a/groundtest/src/main/scala/cachetest.scala b/groundtest/src/main/scala/cachetest.scala index 07dbe9ce..ac6a5c54 100644 --- a/groundtest/src/main/scala/cachetest.scala +++ b/groundtest/src/main/scala/cachetest.scala @@ -43,5 +43,7 @@ class CacheFillTest(implicit p: Parameters) extends GroundTest()(p) when (state === s_prefetch && round_done) { state := s_retrieve } when (state === s_retrieve && round_done) { state := s_finished } - io.finished := (state === s_finished) + io.status.finished := (state === s_finished) + io.status.timeout.valid := Bool(false) + io.status.error.valid := Bool(false) } diff --git a/groundtest/src/main/scala/comparator.scala b/groundtest/src/main/scala/comparator.scala index f32dcbde..f7451236 100644 --- a/groundtest/src/main/scala/comparator.scala +++ b/groundtest/src/main/scala/comparator.scala @@ -208,6 +208,7 @@ class ComparatorClient(val target: Long)(implicit val p: Parameters) extends Mod val tl = new ClientUncachedTileLinkIO() val out = Decoupled(new Grant) val finished = Bool(OUTPUT) + val timeout = Bool(OUTPUT) } val xacts = tlMaxClientXacts @@ -295,15 +296,18 @@ class ComparatorClient(val target: Long)(implicit val p: Parameters) extends Mod timer.io.stop.valid := io.tl.grant.fire() && io.tl.grant.bits.first() timer.io.stop.bits := io.tl.grant.bits.client_xact_id assert(!timer.io.timeout, "Comparator TL client timed out") + io.timeout := timer.io.timeout } class ComparatorSink(implicit val p: Parameters) extends Module with HasComparatorParameters with HasTileLinkParameters + with HasGroundTestConstants { val io = new Bundle { val in = Vec(nTargets, Decoupled(new Grant)).flip val finished = Bool(OUTPUT) + val error = Valid(UInt(width = errorCodeBits)) } // could use a smaller Queue here, but would couple targets flow controls together @@ -321,10 +325,23 @@ class ComparatorSink(implicit val p: Parameters) extends Module printf("%d: %x =/= %x, g_type = %x\n", idx, base.data, g.data, g.g_type) } + val assert_conds = Seq( + g.is_builtin_type, + base.g_type === g.g_type, + base.addr_beat === g.addr_beat || !g.hasData(), + base.data === g.data || !g.hasData()) + assert (g.is_builtin_type, "grant not builtin") assert (base.g_type === g.g_type, "g_type mismatch") assert (base.addr_beat === g.addr_beat || !g.hasData(), "addr_beat mismatch") assert (base.data === g.data || !g.hasData(), "data mismatch") + + assert_conds.zipWithIndex.foreach { case (cond, i) => + when (cond) { + io.error.valid := Bool(true) + io.error.bits := UInt(i) + } + } } when (all_valid) { // Skip the results generated by the block wiping @@ -355,6 +372,13 @@ class ComparatorCore(implicit p: Parameters) extends GroundTest()(p) sink.io.in(index) <> client.io.out client } + val client_timeouts = clients.map(_.io.timeout) - io.finished := source.io.finished && sink.io.finished && clients.map(_.io.finished).reduce(_ && _) + io.status.finished := source.io.finished && sink.io.finished && clients.map(_.io.finished).reduce(_ && _) + io.status.timeout.valid := client_timeouts.reduce(_ || _) + io.status.timeout.bits := MuxCase(UInt(0), + client_timeouts.zipWithIndex.map { + case (timeout, i) => (timeout -> UInt(i)) + }) + io.status.error := sink.io.error } diff --git a/groundtest/src/main/scala/dmatest.scala b/groundtest/src/main/scala/dmatest.scala deleted file mode 100644 index d2c1cbb9..00000000 --- a/groundtest/src/main/scala/dmatest.scala +++ /dev/null @@ -1,231 +0,0 @@ -package groundtest - -import Chisel._ -import uncore.tilelink._ -import uncore.devices._ -import uncore.devices.DmaRequest._ -import uncore.util._ -import uncore.constants._ -import rocket._ -import junctions.{PAddrBits, HasAddrMapParameters} -import cde.{Parameters, Field} -import scala.math.max - -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 class DmaStreamTestConfig( - source: Int, dest: Int, len: Int, size: Int) - -case object DmaTestSet extends Field[Seq[DmaTestCase]] -case object DmaTestDataStart extends Field[Int] -case object DmaTestDataStride extends Field[Int] - -case object DmaStreamTestSettings extends Field[DmaStreamTestConfig] - -class DmaStatusReg(implicit val p: Parameters) extends Module - with HasDmaParameters with HasTileLinkParameters { - - val io = new Bundle { - val csr = (new RoCCCSRs).flip - val incr_outstanding = Bool(INPUT) - val xact_outstanding = Bool(OUTPUT) - val resp_status = UInt(OUTPUT, dmaStatusBits) - } - - val status_reg = Reg(UInt(width = dmaStatusBits)) - - val outstanding_cnt = TwoWayCounter( - io.incr_outstanding, io.csr.wen, tlMaxClientXacts) - - when (io.csr.wen) { status_reg := io.csr.wdata } - - io.xact_outstanding := outstanding_cnt > UInt(0) - io.resp_status := status_reg - io.csr.rdata(0) := status_reg -} - -class DmaStreamTest(implicit p: Parameters) extends GroundTest()(p) - with HasDmaParameters with HasCoreParameters with HasAddrMapParameters { - val (s_start :: s_setup_req :: s_setup_wait :: - s_stream_out :: s_stream_in :: s_stream_wait :: - s_check_req :: s_check_wait :: s_done :: Nil) = Enum(Bits(), 9) - val state = Reg(init = s_start) - val lo_base = addrMap("devices:loopback").start - val conf = p(DmaStreamTestSettings) - - val test_data = Vec.tabulate(conf.len) { i => UInt(i * 8, conf.size * 8) } - - val (req_index, req_done) = Counter(io.cache.head.req.fire(), conf.len) - val (resp_index, resp_done) = Counter(io.cache.head.resp.fire(), conf.len) - - val out_req = ClientDmaRequest( - cmd = DMA_CMD_SOUT, - src_start = UInt(conf.source), - dst_start = UInt(lo_base), - segment_size = UInt(conf.len * conf.size), - word_size = UInt(log2Up(conf.size))) - - val in_req = ClientDmaRequest( - cmd = DMA_CMD_SIN, - src_start = UInt(lo_base), - dst_start = UInt(conf.dest), - segment_size = UInt(conf.len * conf.size), - word_size = UInt(log2Up(conf.size))) - - val frontend = Module(new DmaFrontend) - frontend.io.cpu.req.valid := (state === s_stream_out) || (state === s_stream_in) - frontend.io.cpu.req.bits := Mux(state === s_stream_out, out_req, in_req) - - io.ptw.head <> frontend.io.ptw - io.mem.head <> frontend.io.mem - - val status_reg = Module(new DmaStatusReg) - //status_reg.io.csr <> io.csr - status_reg.io.incr_outstanding := frontend.io.incr_outstanding - - val cache_addr_base = Mux(state === s_setup_req, UInt(conf.source), UInt(conf.dest)) - val cache_req = io.cache.head.req - - cache_req.valid := (state === s_setup_req) || (state === s_check_req) - cache_req.bits.addr := cache_addr_base + Cat(req_index, UInt(0, log2Up(conf.size))) - cache_req.bits.data := test_data(req_index) - cache_req.bits.typ := UInt(log2Up(conf.size)) - cache_req.bits.cmd := Mux(state === s_setup_req, M_XWR, M_XRD) - - when (state === s_start) { state := s_setup_req } - when (state === s_setup_req && req_done) { state := s_setup_wait } - when (state === s_check_req && req_done) { state := s_check_wait } - when (state === s_setup_wait && resp_done) { state := s_stream_out } - when (state === s_check_wait && resp_done) { state := s_done } - - when (frontend.io.cpu.req.fire()) { - state := Mux(state === s_stream_out, s_stream_in, s_stream_wait) - } - - val dma_done = (state === s_stream_wait) && - !frontend.io.busy && !status_reg.io.xact_outstanding - - when (dma_done) { state := s_check_req } - - val resp_data = io.cache.head.resp.bits.data(conf.size * 8 - 1, 0) - assert(!io.cache.head.resp.valid || !io.cache.head.resp.bits.has_data || - resp_data === test_data(resp_index), - "Result data streamed in does not match data streamed out") - assert(!frontend.io.cpu.resp.valid || frontend.io.cpu.resp.bits.status === UInt(0), - "Frontend error response") - - io.finished := (state === s_done) -} - -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) - - 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, DMA_CMD_PFR, DMA_CMD_COPY), - src_start = sourceAddrs(testIdx), - dst_start = destAddrs(testIdx), - segment_size = transferLengths(testIdx)) - - io.ptw.head <> frontend.io.ptw - io.mem.head <> frontend.io.mem - - val status_reg = Module(new DmaStatusReg) - //status_reg.io.csr <> io.csr - status_reg.io.incr_outstanding := frontend.io.incr_outstanding - - val dma_done = !frontend.io.busy && !status_reg.io.xact_outstanding - - val cache_resp = io.cache.head.resp - val cache_req = io.cache.head.req - cache_req.valid := (state === s_fill_req) || (state === s_check_req) - cache_req.bits.addr := req_addr - cache_req.bits.data := req_data - cache_req.bits.typ := MT_W - cache_req.bits.cmd := Mux(state === s_fill_req, M_XWR, M_XRD) - - when (state === s_start) { - req_addr := sourceAddrs(testIdx) - req_data := UInt(dataStart) - bytes_left := transferLengths(testIdx) - state := s_fill_req - } - - when (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 && 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 && dma_done) { - req_addr := destAddrs(testIdx) - req_data := UInt(dataStart) - bytes_left := transferLengths(testIdx) - state := s_check_req - } - - when (state === s_check_resp && 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(!cache_resp.valid || !cache_resp.bits.has_data || - cache_resp.bits.data === req_data, "Received data does not match") - assert(!frontend.io.cpu.resp.valid || frontend.io.cpu.resp.bits.status === UInt(0), - "Frontend error response") - - val cache_timeout = Timer(1000, cache_req.fire(), 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 84aad6a5..9fbb2098 100644 --- a/groundtest/src/main/scala/generator.scala +++ b/groundtest/src/main/scala/generator.scala @@ -39,7 +39,7 @@ class UncachedTileLinkGenerator(id: Int) val io = new Bundle { val mem = new ClientUncachedTileLinkIO - val finished = Bool(OUTPUT) + val status = new GroundTestStatus } val (s_start :: s_put :: s_get :: s_finished :: Nil) = Enum(Bits(), 4) @@ -61,7 +61,9 @@ class UncachedTileLinkGenerator(id: Int) val timeout = Timer(genTimeout, io.mem.acquire.fire(), io.mem.grant.fire()) assert(!timeout, s"Uncached generator ${id} timed out waiting for grant") - io.finished := (state === s_finished) + io.status.finished := (state === s_finished) + io.status.timeout.valid := timeout + io.status.timeout.bits := UInt(id) val part_of_full_addr = if (log2Ceil(nGens) > 0) { @@ -99,17 +101,22 @@ class UncachedTileLinkGenerator(id: Int) operand_size = wordSize, alloc = Bool(false)) - io.mem.acquire.valid := sending && !io.finished + io.mem.acquire.valid := sending && !io.status.finished io.mem.acquire.bits := Mux(state === s_put, put_acquire, get_acquire) - io.mem.grant.ready := !sending && !io.finished + io.mem.grant.ready := !sending && !io.status.finished def wordFromBeat(addr: UInt, dat: UInt) = { val shift = Cat(beatOffset(addr), UInt(0, wordOffset + 3)) (dat >> shift)(genWordBits - 1, 0) } - assert(!io.mem.grant.valid || state =/= s_get || - wordFromBeat(full_addr, io.mem.grant.bits.data) === word_data, + val data_mismatch = io.mem.grant.fire() && state === s_get && + wordFromBeat(full_addr, io.mem.grant.bits.data) =/= word_data + + io.status.error.valid := data_mismatch + io.status.error.bits := UInt(id) + + assert(!data_mismatch, s"Get received incorrect data in uncached generator ${id}") def beatOffset(addr: UInt) = // TODO zero-width @@ -121,11 +128,13 @@ class HellaCacheGenerator(id: Int) (implicit p: Parameters) extends L1HellaCacheModule()(p) with HasGeneratorParameters { val io = new Bundle { val mem = new HellaCacheIO - val finished = Bool(OUTPUT) + val status = new GroundTestStatus } val timeout = Timer(genTimeout, io.mem.req.fire(), io.mem.resp.valid) assert(!timeout, s"Cached generator ${id} timed out waiting for response") + io.status.timeout.valid := timeout + io.status.timeout.bits := UInt(id) val (s_start :: s_write :: s_read :: s_finished :: Nil) = Enum(Bits(), 4) val state = Reg(init = s_start) @@ -143,7 +152,7 @@ class HellaCacheGenerator(id: Int) val req_addr = UInt(startAddress) + Cat(req_cnt, part_of_req_addr) val req_data = Cat(UInt(id, log2Up(nGens)), req_addr) - io.mem.req.valid := sending && !io.finished + io.mem.req.valid := sending && !io.status.finished io.mem.req.bits.addr := req_addr io.mem.req.bits.data := req_data io.mem.req.bits.typ := wordSize @@ -157,7 +166,7 @@ class HellaCacheGenerator(id: Int) when (req_wrap) { state := Mux(state === s_write, s_read, s_finished) } - io.finished := (state === s_finished) + io.status.finished := (state === s_finished) def data_match(recv: Bits, expected: Bits): Bool = { val recv_resized = Wire(Bits(width = genWordBits)) @@ -168,8 +177,13 @@ class HellaCacheGenerator(id: Int) recv_resized === exp_resized } - assert(!io.mem.resp.valid || !io.mem.resp.bits.has_data || - data_match(io.mem.resp.bits.data, req_data), + val data_mismatch = io.mem.resp.valid && io.mem.resp.bits.has_data && + !data_match(io.mem.resp.bits.data, req_data) + + io.status.error.valid := data_mismatch + io.status.error.bits := UInt(id) + + assert(!data_mismatch, s"Received incorrect data in cached generator ${id}") } @@ -193,6 +207,6 @@ class GeneratorTest(implicit p: Parameters) io.cache <> cached.map(_.io.mem) io.mem <> uncached.map(_.io.mem) - val gen_finished = cached.map(_.io.finished) ++ uncached.map(_.io.finished) - io.finished := gen_finished.reduce(_ && _) + val gen_debug = cached.map(_.io.status) ++ uncached.map(_.io.status) + io.status := DebugCombiner(gen_debug) } diff --git a/groundtest/src/main/scala/nastitest.scala b/groundtest/src/main/scala/nastitest.scala index ef662464..a6011c17 100644 --- a/groundtest/src/main/scala/nastitest.scala +++ b/groundtest/src/main/scala/nastitest.scala @@ -13,7 +13,7 @@ class NastiGenerator(id: Int)(implicit val p: Parameters) extends Module with HasGeneratorParameters { val io = new Bundle { - val finished = Bool(OUTPUT) + val status = new GroundTestStatus val mem = new NastiIO } @@ -65,7 +65,7 @@ class NastiGenerator(id: Int)(implicit val p: Parameters) extends Module io.mem.r.ready := Bool(true) io.mem.b.ready := Bool(true) - io.finished := (state === s_finish) + io.status.finished := (state === s_finish) val (read_resp_idx, read_resp_done) = Counter(io.mem.r.fire(), maxRequests) val read_resp_addr = UInt(startAddress) + Cat(read_resp_idx, part_of_addr) @@ -73,8 +73,10 @@ class NastiGenerator(id: Int)(implicit val p: Parameters) extends Module val read_shift = Cat(read_offset, UInt(0, 3)) val read_data = (io.mem.r.bits.data >> read_shift)(genWordBits - 1, 0) - assert(!io.mem.r.valid || read_data === ref_data(read_resp_idx), - "NASTI Test: results do not match") + val data_mismatch = io.mem.r.valid && read_data =/= ref_data(read_resp_idx) + assert(!data_mismatch, "NASTI Test: results do not match") + io.status.error.valid := data_mismatch + io.status.error.bits := UInt(1) when (state === s_start) { state := s_write_addr } when (io.mem.aw.fire()) { state := s_write_data } @@ -96,6 +98,9 @@ class NastiGenerator(id: Int)(implicit val p: Parameters) extends Module w_timer.io.stop.valid := io.mem.b.fire() w_timer.io.stop.bits := io.mem.b.bits.id assert(!w_timer.io.timeout, "NASTI Write timed out") + + io.status.timeout.valid := r_timer.io.timeout || w_timer.io.timeout + io.status.timeout.bits := Mux(r_timer.io.timeout, UInt(1), UInt(2)) } class NastiConverterTest(implicit p: Parameters) extends GroundTest()(p) @@ -112,5 +117,5 @@ class NastiConverterTest(implicit p: Parameters) extends GroundTest()(p) converter.io.nasti <> test.io.mem TileLinkWidthAdapter(io.mem.head, converter.io.tl) - io.finished := test.io.finished + io.status := test.io.status } diff --git a/groundtest/src/main/scala/regression.scala b/groundtest/src/main/scala/regression.scala index 3822d293..f7e60594 100644 --- a/groundtest/src/main/scala/regression.scala +++ b/groundtest/src/main/scala/regression.scala @@ -13,6 +13,7 @@ class RegressionIO(implicit val p: Parameters) extends ParameterizedBundle()(p) val cache = new HellaCacheIO val mem = new ClientUncachedTileLinkIO val finished = Bool(OUTPUT) + val errored = Bool(OUTPUT) } abstract class Regression(implicit val p: Parameters) @@ -178,10 +179,11 @@ class NoAllocPutHitRegression(implicit p: Parameters) extends Regression()(p) { } } - assert(!io.mem.grant.valid || !gnt.hasData() || gnt.data === test_data, - "NoAllocPutHitRegression: data does not match") + val data_mismatch = io.mem.grant.fire() && gnt.hasData() && gnt.data =/= test_data + assert(!data_mismatch, "NoAllocPutHitRegression: data does not match") io.finished := (state === s_done) + io.errored := data_mismatch disableCache() } @@ -249,9 +251,10 @@ class MixedAllocPutRegression(implicit p: Parameters) extends Regression()(p) { io.finished := (state === s_done) - assert(state =/= s_get_wait || !io.mem.grant.valid || - io.mem.grant.bits.data === test_data(io.mem.grant.bits.client_xact_id), - "MixedAllocPutRegression: data mismatch") + val data_mismatch = state === s_get_wait && io.mem.grant.fire() && + io.mem.grant.bits.data =/= test_data(io.mem.grant.bits.client_xact_id) + assert(!data_mismatch, "MixedAllocPutRegression: data mismatch") + io.errored := data_mismatch disableCache() } @@ -347,11 +350,10 @@ class WriteMaskedPutBlockRegression(implicit p: Parameters) extends Regression() io.finished := (state === s_done) - assert(!io.mem.grant.valid || - !io.mem.grant.bits.hasData() || - stage === UInt(0) || - io.mem.grant.bits.data === get_data, - "WriteMaskedPutBlockRegression: data does not match") + val data_mismatch = io.mem.grant.fire() && io.mem.grant.bits.hasData() && + state =/= UInt(0) && io.mem.grant.bits.data =/= get_data + assert(!data_mismatch, "WriteMaskedPutBlockRegression: data does not match") + io.errored := data_mismatch } /* Make sure a prefetch that hits returns immediately. */ @@ -379,6 +381,7 @@ class PrefetchHitRegression(implicit p: Parameters) extends Regression()(p) { when (sending && pf_done) { sending := Bool(false) } io.finished := acked.andR + io.errored := Bool(false) } /* This tests the sort of access the pattern that Hwacha uses. @@ -408,8 +411,9 @@ class SequentialSameIdGetRegression(implicit p: Parameters) extends Regression() io.finished := finished - assert(!io.mem.grant.valid || io.mem.grant.bits.addr_beat === recv_cnt, - "SequentialSameIdGetRegression: grant received out of order") + val beat_mismatch = io.mem.grant.fire() && io.mem.grant.bits.addr_beat =/= recv_cnt + assert(!beat_mismatch, "SequentialSameIdGetRegression: grant received out of order") + io.errored := beat_mismatch } /* Test that a writeback will occur by writing nWays + 1 blocks to the same @@ -463,9 +467,10 @@ class WritebackRegression(implicit p: Parameters) extends Regression()(p) { io.finished := (state === s_done) - assert(!io.mem.grant.valid || !io.mem.grant.bits.hasData() || - io.mem.grant.bits.data === data(ack_cnt), - "WritebackRegression: incorrect data") + val data_mismatch = io.mem.grant.fire() && io.mem.grant.bits.hasData() && + io.mem.grant.bits.data =/= data(ack_cnt) + assert(!data_mismatch, "WritebackRegression: incorrect data") + io.errored := data_mismatch } class ReleaseRegression(implicit p: Parameters) extends Regression()(p) { @@ -506,9 +511,10 @@ class ReleaseRegression(implicit p: Parameters) extends Regression()(p) { io.finished := (state === s_done) - assert(!io.cache.resp.valid || !io.cache.resp.bits.has_data || - io.cache.resp.bits.data === data(resp_idx), - "ReleaseRegression: data mismatch") + val data_mismatch = io.cache.resp.valid && io.cache.resp.bits.has_data && + io.cache.resp.bits.data =/= data(resp_idx) + assert(!data_mismatch, "ReleaseRegression: data mismatch") + io.errored := data_mismatch } class PutBeforePutBlockRegression(implicit p: Parameters) extends Regression()(p) { @@ -548,6 +554,7 @@ class PutBeforePutBlockRegression(implicit p: Parameters) extends Regression()(p when (all_acked) { state := s_finished } io.finished := (state === s_finished) + io.errored := Bool(false) } object RegressionTests { @@ -610,6 +617,8 @@ class RegressionTest(implicit p: Parameters) extends GroundTest()(p) { io.cache.head.req.valid := regress.io.cache.req.valid io.cache.head.req.bits := regress.io.cache.req.bits io.cache.head.invalidate_lr := regress.io.cache.invalidate_lr + io.status.error.valid := regress.io.errored + io.status.error.bits := UInt(i) cur_finished := regress.io.finished } } @@ -620,11 +629,18 @@ class RegressionTest(implicit p: Parameters) extends GroundTest()(p) { } when (start) { start := Bool(false) } - io.finished := all_done - val timeout = Timer(5000, start, cur_finished) assert(!timeout, "Regression timed out") + io.status.finished := all_done + io.status.timeout.valid := timeout + io.status.timeout.bits := UInt(0) + assert(!(all_done && io.mem.head.grant.valid), "Getting grant after test completion") + + when (all_done) { + io.status.error.valid := io.mem.head.grant.valid + io.status.error.bits := UInt(regressions.size) + } } diff --git a/groundtest/src/main/scala/tile.scala b/groundtest/src/main/scala/tile.scala index e2203f7a..9d2c5859 100644 --- a/groundtest/src/main/scala/tile.scala +++ b/groundtest/src/main/scala/tile.scala @@ -16,6 +16,11 @@ case class GroundTestTileSettings( case object GroundTestKey extends Field[Seq[GroundTestTileSettings]] case object GroundTestId extends Field[Int] +trait HasGroundTestConstants { + val timeoutCodeBits = 4 + val errorCodeBits = 4 +} + trait HasGroundTestParameters extends HasAddrMapParameters { implicit val p: Parameters val tileId = p(GroundTestId) @@ -69,12 +74,18 @@ class DummyPTW(n: Int)(implicit p: Parameters) extends CoreModule()(p) { } } +class GroundTestStatus extends Bundle with HasGroundTestConstants { + val finished = Bool(OUTPUT) + val timeout = Valid(UInt(width = timeoutCodeBits)) + val error = Valid(UInt(width = errorCodeBits)) +} + class GroundTestIO(implicit val p: Parameters) extends ParameterizedBundle()(p) with HasGroundTestParameters { val cache = Vec(nCached, new HellaCacheIO) val mem = Vec(nUncached, new ClientUncachedTileLinkIO) val ptw = Vec(nPTW, new TLBPTWIO) - val finished = Bool(OUTPUT) + val status = new GroundTestStatus } abstract class GroundTest(implicit val p: Parameters) extends Module @@ -113,7 +124,7 @@ class GroundTestTile(resetSignal: Bool) ptwPorts += dcache_io.ptw } - when (test.io.finished) { stop() } + when (test.io.status.finished) { stop() } if (ptwPorts.size > 0) { val ptw = Module(new DummyPTW(ptwPorts.size)) diff --git a/groundtest/src/main/scala/tracegen.scala b/groundtest/src/main/scala/tracegen.scala index ca42f580..dd9ce022 100644 --- a/groundtest/src/main/scala/tracegen.scala +++ b/groundtest/src/main/scala/tracegen.scala @@ -178,6 +178,7 @@ class TraceGenerator(id: Int) with HasTraceGenParams { val io = new Bundle { val finished = Bool(OUTPUT) + val timeout = Bool(OUTPUT) val mem = new HellaCacheIO } @@ -540,6 +541,7 @@ class TraceGenerator(id: Int) } io.finished := Bool(false) + io.timeout := timeout } // ======================= @@ -552,5 +554,8 @@ class GroundTestTraceGenerator(implicit p: Parameters) val traceGen = Module(new TraceGenerator(p(GroundTestId))) io.cache.head <> traceGen.io.mem - io.finished := traceGen.io.finished + io.status.finished := traceGen.io.finished + io.status.timeout.valid := traceGen.io.timeout + io.status.timeout.bits := UInt(0) + io.status.error.valid := Bool(false) } diff --git a/groundtest/src/main/scala/unittest.scala b/groundtest/src/main/scala/unittest.scala index 4950d212..5144dbb0 100644 --- a/groundtest/src/main/scala/unittest.scala +++ b/groundtest/src/main/scala/unittest.scala @@ -576,10 +576,16 @@ class UnitTestSuite(implicit p: Parameters) extends GroundTest()(p) { when (state === s_idle) { state := s_start } when (state === s_start) { state := s_wait } + io.status.timeout.valid := Bool(false) tests.zipWithIndex.foreach { case (mod, i) => mod.io.start := (state === s_start) val timeout = Timer(1000, mod.io.start, mod.io.finished) assert(!timeout, s"UnitTest $i timed out") + when (timeout) { + io.status.timeout.valid := Bool(true) + io.status.timeout.bits := UInt(i) + } } - io.finished := tests.map(_.io.finished).reduce(_ && _) + io.status.finished := tests.map(_.io.finished).reduce(_ && _) + io.status.error.valid := Bool(false) } diff --git a/groundtest/src/main/scala/util.scala b/groundtest/src/main/scala/util.scala index ca6fb411..864805f8 100644 --- a/groundtest/src/main/scala/util.scala +++ b/groundtest/src/main/scala/util.scala @@ -154,3 +154,26 @@ object Frequency { return result } } + +object ValidMux { + def apply[T <: Data](v1: ValidIO[T], v2: ValidIO[T]*): ValidIO[T] = { + apply(v1 +: v2.toSeq) + } + def apply[T <: Data](valids: Seq[ValidIO[T]]): ValidIO[T] = { + val out = Wire(Valid(valids.head.bits)) + out.valid := valids.map(_.valid).reduce(_ || _) + out.bits := MuxCase(valids.head.bits, + valids.map(v => (v.valid -> v.bits))) + out + } +} + +object DebugCombiner { + def apply(debugs: Seq[GroundTestStatus]): GroundTestStatus = { + val out = Wire(new GroundTestStatus) + out.finished := debugs.map(_.finished).reduce(_ || _) + out.timeout := ValidMux(debugs.map(_.timeout)) + out.error := ValidMux(debugs.map(_.error)) + out + } +}