export more detailed status data from GroundTest
This commit is contained in:
		| @@ -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) | ||||
| } | ||||
|   | ||||
| @@ -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 | ||||
| } | ||||
|   | ||||
| @@ -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") | ||||
| } | ||||
| @@ -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) | ||||
| } | ||||
|   | ||||
| @@ -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 | ||||
| } | ||||
|   | ||||
| @@ -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) | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -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)) | ||||
|   | ||||
| @@ -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) | ||||
| } | ||||
|   | ||||
| @@ -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) | ||||
| } | ||||
|   | ||||
| @@ -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 | ||||
|   } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user