From 661015a78d6cefada1c07e126faec6f49dd7c20a Mon Sep 17 00:00:00 2001 From: "Wesley W. Terpstra" Date: Thu, 27 Apr 2017 14:40:49 -0700 Subject: [PATCH] axi4: switch arbiter to round robin --- src/main/scala/uncore/axi4/ToTL.scala | 2 +- src/main/scala/uncore/tilelink2/Arbiter.scala | 58 +++++++++++++++++-- 2 files changed, 53 insertions(+), 7 deletions(-) diff --git a/src/main/scala/uncore/axi4/ToTL.scala b/src/main/scala/uncore/axi4/ToTL.scala index d1edd5b6..088b24e7 100644 --- a/src/main/scala/uncore/axi4/ToTL.scala +++ b/src/main/scala/uncore/axi4/ToTL.scala @@ -105,7 +105,7 @@ class AXI4ToTL()(implicit p: Parameters) extends LazyModule when (in.aw.fire() && s) { r := r + UInt(1) } } - TLArbiter(TLArbiter.lowestIndexFirst)(out.a, (UInt(0), r_out), (in.aw.bits.len, w_out)) + TLArbiter(TLArbiter.roundRobin)(out.a, (UInt(0), r_out), (in.aw.bits.len, w_out)) val ok_b = Wire(in.b) val ok_r = Wire(in.r) diff --git a/src/main/scala/uncore/tilelink2/Arbiter.scala b/src/main/scala/uncore/tilelink2/Arbiter.scala index f468c26a..2a99f843 100644 --- a/src/main/scala/uncore/tilelink2/Arbiter.scala +++ b/src/main/scala/uncore/tilelink2/Arbiter.scala @@ -3,15 +3,28 @@ package uncore.tilelink2 import Chisel._ +import config._ import diplomacy._ object TLArbiter { - // (valids, granted) => readys - type Policy = (Seq[Bool], Bool) => Seq[Bool] + // (valids, select) => readys + type Policy = (Integer, UInt, Bool) => UInt - val lowestIndexFirst: Policy = (valids, granted) => - valids.scanLeft(Bool(true))(_ && !_).init + val lowestIndexFirst: Policy = (width, valids, select) => ~(leftOR(valids) << 1)(width-1, 0) + + val roundRobin: Policy = (width, valids, select) => { + val valid = valids(width-1, 0) + assert (valid === valids) + val mask = RegInit(~UInt(0, width=width)) + val filter = Cat(valid & ~mask, valid) + val unready = (rightOR(filter, width*2) >> 1) | (mask << width) // last right shift unneeded + val readys = ~((unready >> width) & unready(width-1, 0)) + when (select && valid.orR) { + mask := leftOR(readys & valid, width) + } + readys(width-1, 0) + } def lowestFromSeq[T <: TLChannel](edge: TLEdge, sink: DecoupledIO[T], sources: Seq[DecoupledIO[T]]) { apply(lowestIndexFirst)(sink, sources.map(s => (edge.numBeats1(s.bits), s)):_*) @@ -21,6 +34,10 @@ object TLArbiter apply(lowestIndexFirst)(sink, sources.toList.map(s => (edge.numBeats1(s.bits), s)):_*) } + def robin[T <: TLChannel](edge: TLEdge, sink: DecoupledIO[T], sources: DecoupledIO[T]*) { + apply(roundRobin)(sink, sources.toList.map(s => (edge.numBeats1(s.bits), s)):_*) + } + def apply[T <: Data](policy: Policy)(sink: DecoupledIO[T], sources: (UInt, DecoupledIO[T])*) { if (sources.isEmpty) { sink.valid := Bool(false) @@ -37,13 +54,13 @@ object TLArbiter // Who wants access to the sink? val valids = sourcesIn.map(_.valid) // Arbitrate amongst the requests - val readys = Vec(policy(valids, latch)) + val readys = Vec(policy(valids.size, Cat(valids.reverse), latch).toBools) // Which request wins arbitration? val winner = Vec((readys zip valids) map { case (r,v) => r&&v }) // Confirm the policy works properly require (readys.size == valids.size) - // Never two winner + // Never two winners val prefixOR = winner.scanLeft(Bool(false))(_||_).init assert((prefixOR zip winner) map { case (p,w) => !p || !w } reduce {_ && _}) // If there was any request, there is a winner @@ -73,3 +90,32 @@ object TLArbiter } } } + +/** Synthesizeable unit tests */ +import unittest._ + +class TestRobin()(implicit p: Parameters) extends UnitTest(timeout = 500000) { + val sources = Wire(Vec(6, DecoupledIO(UInt(width=3)))) + val sink = Wire(DecoupledIO(UInt(width=3))) + val count = RegInit(UInt(0, width=8)) + + val lfsr = LFSR16(Bool(true)) + val valid = lfsr(0) + val ready = lfsr(15) + + sources.zipWithIndex.map { case (z, i) => z.bits := UInt(i) } + sources(0).valid := valid + sources(1).valid := Bool(false) + sources(2).valid := valid + sources(3).valid := valid + sources(4).valid := Bool(false) + sources(5).valid := valid + sink.ready := ready + + TLArbiter(TLArbiter.roundRobin)(sink, sources.zipWithIndex.map { case (z, i) => (UInt(i), z) }:_*) + when (sink.fire()) { printf("TestRobin: %d\n", sink.bits) } + when (!sink.fire()) { printf("TestRobin: idle (%d %d)\n", valid, ready) } + + count := count + UInt(1) + io.finished := count >= UInt(128) +}