2016-11-28 01:16:37 +01:00
|
|
|
// See LICENSE.SiFive for license details.
|
2016-09-22 00:28:49 +02:00
|
|
|
|
|
|
|
package uncore.tilelink2
|
|
|
|
|
|
|
|
import Chisel._
|
2017-04-27 23:40:49 +02:00
|
|
|
import config._
|
2016-10-04 00:17:36 +02:00
|
|
|
import diplomacy._
|
2016-09-22 00:28:49 +02:00
|
|
|
|
|
|
|
object TLArbiter
|
|
|
|
{
|
2017-04-27 23:40:49 +02:00
|
|
|
// (valids, select) => readys
|
|
|
|
type Policy = (Integer, UInt, Bool) => UInt
|
2016-09-22 00:28:49 +02:00
|
|
|
|
2017-04-27 23:40:49 +02:00
|
|
|
val lowestIndexFirst: Policy = (width, valids, select) => ~(leftOR(valids) << 1)(width-1, 0)
|
|
|
|
|
2017-06-02 00:26:04 +02:00
|
|
|
val roundRobin: Policy = (width, valids, select) => if (width == 1) UInt(1, width=1) else {
|
2017-04-27 23:40:49 +02:00
|
|
|
val valid = valids(width-1, 0)
|
|
|
|
assert (valid === valids)
|
|
|
|
val mask = RegInit(~UInt(0, width=width))
|
|
|
|
val filter = Cat(valid & ~mask, valid)
|
2017-06-02 00:26:04 +02:00
|
|
|
val unready = (rightOR(filter, width*2, width) >> 1) | (mask << width)
|
2017-04-27 23:40:49 +02:00
|
|
|
val readys = ~((unready >> width) & unready(width-1, 0))
|
|
|
|
when (select && valid.orR) {
|
|
|
|
mask := leftOR(readys & valid, width)
|
|
|
|
}
|
|
|
|
readys(width-1, 0)
|
|
|
|
}
|
2016-09-22 00:28:49 +02:00
|
|
|
|
2016-11-19 04:01:36 +01:00
|
|
|
def lowestFromSeq[T <: TLChannel](edge: TLEdge, sink: DecoupledIO[T], sources: Seq[DecoupledIO[T]]) {
|
|
|
|
apply(lowestIndexFirst)(sink, sources.map(s => (edge.numBeats1(s.bits), s)):_*)
|
|
|
|
}
|
|
|
|
|
|
|
|
def lowest[T <: TLChannel](edge: TLEdge, sink: DecoupledIO[T], sources: DecoupledIO[T]*) {
|
|
|
|
apply(lowestIndexFirst)(sink, sources.toList.map(s => (edge.numBeats1(s.bits), s)):_*)
|
|
|
|
}
|
|
|
|
|
2017-04-27 23:40:49 +02:00
|
|
|
def robin[T <: TLChannel](edge: TLEdge, sink: DecoupledIO[T], sources: DecoupledIO[T]*) {
|
|
|
|
apply(roundRobin)(sink, sources.toList.map(s => (edge.numBeats1(s.bits), s)):_*)
|
|
|
|
}
|
|
|
|
|
2016-10-13 03:09:01 +02:00
|
|
|
def apply[T <: Data](policy: Policy)(sink: DecoupledIO[T], sources: (UInt, DecoupledIO[T])*) {
|
2016-09-24 01:24:29 +02:00
|
|
|
if (sources.isEmpty) {
|
|
|
|
sink.valid := Bool(false)
|
|
|
|
} else {
|
|
|
|
val pairs = sources.toList
|
|
|
|
val beatsIn = pairs.map(_._1)
|
|
|
|
val sourcesIn = pairs.map(_._2)
|
2016-09-22 00:28:49 +02:00
|
|
|
|
2016-09-24 01:24:29 +02:00
|
|
|
// The number of beats which remain to be sent
|
|
|
|
val beatsLeft = RegInit(UInt(0))
|
|
|
|
val idle = beatsLeft === UInt(0)
|
2016-10-13 03:35:16 +02:00
|
|
|
val latch = idle && sink.ready // winner (if any) claims sink
|
2016-09-22 00:28:49 +02:00
|
|
|
|
2016-09-24 01:24:29 +02:00
|
|
|
// Who wants access to the sink?
|
|
|
|
val valids = sourcesIn.map(_.valid)
|
|
|
|
// Arbitrate amongst the requests
|
2017-04-27 23:40:49 +02:00
|
|
|
val readys = Vec(policy(valids.size, Cat(valids.reverse), latch).toBools)
|
2016-09-24 01:24:29 +02:00
|
|
|
// Which request wins arbitration?
|
2016-10-13 03:37:24 +02:00
|
|
|
val winner = Vec((readys zip valids) map { case (r,v) => r&&v })
|
2016-09-22 00:28:49 +02:00
|
|
|
|
2016-09-24 01:24:29 +02:00
|
|
|
// Confirm the policy works properly
|
|
|
|
require (readys.size == valids.size)
|
2017-04-27 23:40:49 +02:00
|
|
|
// Never two winners
|
2016-10-13 03:37:24 +02:00
|
|
|
val prefixOR = winner.scanLeft(Bool(false))(_||_).init
|
|
|
|
assert((prefixOR zip winner) map { case (p,w) => !p || !w } reduce {_ && _})
|
2016-09-24 01:24:29 +02:00
|
|
|
// If there was any request, there is a winner
|
2016-10-13 03:37:24 +02:00
|
|
|
assert (!valids.reduce(_||_) || winner.reduce(_||_))
|
2016-09-22 00:28:49 +02:00
|
|
|
|
2016-09-24 01:24:29 +02:00
|
|
|
// Track remaining beats
|
2016-10-13 03:37:24 +02:00
|
|
|
val maskedBeats = (winner zip beatsIn) map { case (w,b) => Mux(w, b, UInt(0)) }
|
2016-09-24 01:24:29 +02:00
|
|
|
val initBeats = maskedBeats.reduce(_ | _) // no winner => 0 beats
|
2016-10-13 03:35:16 +02:00
|
|
|
beatsLeft := Mux(latch, initBeats, beatsLeft - sink.fire())
|
2016-09-22 00:28:49 +02:00
|
|
|
|
2016-09-24 01:24:29 +02:00
|
|
|
// The one-hot source granted access in the previous cycle
|
|
|
|
val state = RegInit(Vec.fill(sources.size)(Bool(false)))
|
2016-10-13 03:37:24 +02:00
|
|
|
val muxState = Mux(idle, winner, state)
|
2016-09-24 01:24:29 +02:00
|
|
|
state := muxState
|
2016-09-22 00:28:49 +02:00
|
|
|
|
2016-09-24 01:24:29 +02:00
|
|
|
if (sources.size > 1) {
|
|
|
|
val allowed = Mux(idle, readys, state)
|
|
|
|
(sourcesIn zip allowed) foreach { case (s, r) =>
|
|
|
|
s.ready := sink.ready && r
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
sourcesIn(0).ready := sink.ready
|
2016-09-22 00:28:49 +02:00
|
|
|
}
|
|
|
|
|
2016-10-13 03:35:16 +02:00
|
|
|
sink.valid := Mux(idle, valids.reduce(_||_), Mux1H(state, valids))
|
2016-09-24 01:24:29 +02:00
|
|
|
sink.bits := Mux1H(muxState, sourcesIn.map(_.bits))
|
|
|
|
}
|
2016-09-22 00:28:49 +02:00
|
|
|
}
|
|
|
|
}
|
2017-04-27 23:40:49 +02:00
|
|
|
|
|
|
|
/** Synthesizeable unit tests */
|
|
|
|
import unittest._
|
|
|
|
|
2017-05-17 20:56:01 +02:00
|
|
|
class TestRobin(txns: Int = 128, timeout: Int = 500000)(implicit p: Parameters) extends UnitTest(timeout) {
|
2017-04-27 23:40:49 +02:00
|
|
|
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)
|
2017-05-17 20:56:01 +02:00
|
|
|
io.finished := count >= UInt(txns)
|
2017-04-27 23:40:49 +02:00
|
|
|
}
|