1
0
rocket-chip/src/main/scala/uncore/tilelink2/Arbiter.scala
2016-11-27 22:15:43 -08:00

76 lines
2.6 KiB
Scala

// See LICENSE.SiFive for license details.
package uncore.tilelink2
import Chisel._
import diplomacy._
object TLArbiter
{
// (valids, granted) => readys
type Policy = (Seq[Bool], Bool) => Seq[Bool]
val lowestIndexFirst: Policy = (valids, granted) =>
valids.scanLeft(Bool(true))(_ && !_).init
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)):_*)
}
def apply[T <: Data](policy: Policy)(sink: DecoupledIO[T], sources: (UInt, DecoupledIO[T])*) {
if (sources.isEmpty) {
sink.valid := Bool(false)
} else {
val pairs = sources.toList
val beatsIn = pairs.map(_._1)
val sourcesIn = pairs.map(_._2)
// The number of beats which remain to be sent
val beatsLeft = RegInit(UInt(0))
val idle = beatsLeft === UInt(0)
val latch = idle && sink.ready // winner (if any) claims sink
// Who wants access to the sink?
val valids = sourcesIn.map(_.valid)
// Arbitrate amongst the requests
val readys = Vec(policy(valids, latch))
// 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
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
assert (!valids.reduce(_||_) || winner.reduce(_||_))
// Track remaining beats
val maskedBeats = (winner zip beatsIn) map { case (w,b) => Mux(w, b, UInt(0)) }
val initBeats = maskedBeats.reduce(_ | _) // no winner => 0 beats
beatsLeft := Mux(latch, initBeats, beatsLeft - sink.fire())
// The one-hot source granted access in the previous cycle
val state = RegInit(Vec.fill(sources.size)(Bool(false)))
val muxState = Mux(idle, winner, state)
state := muxState
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
}
sink.valid := Mux(idle, valids.reduce(_||_), Mux1H(state, valids))
sink.bits := Mux1H(muxState, sourcesIn.map(_.bits))
}
}
}