diff --git a/groundtest/src/main/scala/regression.scala b/groundtest/src/main/scala/regression.scala new file mode 100644 index 00000000..984e59bd --- /dev/null +++ b/groundtest/src/main/scala/regression.scala @@ -0,0 +1,115 @@ +package groundtest + +import Chisel._ +import uncore._ +import junctions.{MMIOBase, ParameterizedBundle} +import cde.Parameters + +class RegressionIO(implicit val p: Parameters) extends GroundTestIO()(p) { + val start = Bool(INPUT) +} + +abstract class Regression(implicit val p: Parameters) extends Module { + val io = new RegressionIO +} + +/** + * This was a bug in which the TileLinkIONarrower logic screwed up + * when a PutBlock request and a narrow Get request are sent to it at the + * same time. Repeating this sequence enough times will cause a queue to + * get filled up and deadlock the system. + */ +class IOGetAfterPutBlockRegression(implicit p: Parameters) + extends Regression()(p) with HasTileLinkParameters { + + val nRuns = 7 + val run = Reg(init = UInt(0, log2Up(nRuns + 1))) + + val (put_beat, put_done) = Counter( + io.mem.acquire.fire() && io.mem.acquire.bits.hasData(), tlDataBeats) + + val started = Reg(init = Bool(false)) + val put_sent = Reg(init = Bool(false)) + val get_sent = Reg(init = Bool(false)) + val put_acked = Reg(init = Bool(false)) + val get_acked = Reg(init = Bool(false)) + val both_acked = put_acked && get_acked + + when (!started && io.start) { started := Bool(true) } + + io.mem.acquire.valid := !put_sent && started + io.mem.acquire.bits := PutBlock( + client_xact_id = UInt(0), + addr_block = UInt(0), + addr_beat = put_beat, + data = UInt(0)) + io.mem.grant.ready := Bool(true) + + io.cache.req.valid := !get_sent && started + io.cache.req.bits.addr := UInt(p(MMIOBase)) + io.cache.req.bits.typ := MT_W + io.cache.req.bits.cmd := M_XRD + io.cache.req.bits.tag := UInt(0) + io.cache.req.bits.kill := Bool(false) + io.cache.req.bits.phys := Bool(true) + + when (put_done) { put_sent := Bool(true) } + when (io.cache.req.fire()) { get_sent := Bool(true) } + when (io.mem.grant.fire()) { put_acked := Bool(true) } + when (io.cache.resp.valid) { get_acked := Bool(true) } + + when (both_acked) { + when (run < UInt(nRuns - 1)) { + put_sent := Bool(false) + get_sent := Bool(false) + } + put_acked := Bool(false) + get_acked := Bool(false) + run := run + UInt(1) + } + + io.finished := (run === UInt(nRuns)) +} + +class RegressionTest(implicit p: Parameters) extends GroundTest()(p) { + + val regressions = Seq( + Module(new IOGetAfterPutBlockRegression)) + val regressIOs = Vec(regressions.map(_.io)) + val regress_idx = Reg(init = UInt(0, log2Up(regressions.size + 1))) + val all_done = (regress_idx === UInt(regressions.size)) + val start = Reg(init = Bool(true)) + + when (start) { start := Bool(false) } + + regressIOs.zipWithIndex.foreach { case (regress, i) => + val me = regress_idx === UInt(i) + regress.start := me && start + regress.mem.acquire.ready := io.mem.acquire.ready && me + regress.mem.grant.valid := io.mem.grant.valid && me + regress.mem.grant.bits := io.mem.grant.bits + regress.cache.req.ready := io.cache.req.ready && me + regress.cache.resp.valid := io.cache.resp.valid && me + } + + val cur_regression = regressIOs(regress_idx) + val cur_acquire = cur_regression.mem.acquire + val cur_grant = cur_regression.mem.grant + val cur_cache_req = cur_regression.cache.req + + io.mem.acquire.valid := cur_acquire.valid + io.mem.acquire.bits := cur_acquire.bits + io.mem.grant.ready := cur_grant.ready + io.cache.req.valid := cur_cache_req.valid + io.cache.req.bits := cur_cache_req.bits + + when (cur_regression.finished && !all_done) { + start := Bool(true) + regress_idx := regress_idx + UInt(1) + } + + io.finished := all_done + + val timeout = Timer(5000, start, cur_regression.finished) + assert(!timeout, "Regression timed out") +}