70 lines
2.2 KiB
Scala
70 lines
2.2 KiB
Scala
|
// See LICENSE for license details.
|
||
|
|
||
|
package uncore.tilelink2
|
||
|
|
||
|
import Chisel._
|
||
|
import chisel3.util.IrrevocableIO
|
||
|
|
||
|
object TLArbiter
|
||
|
{
|
||
|
// (valids, idle) => readys
|
||
|
type Policy = (Seq[Bool], Bool) => Seq[Bool]
|
||
|
|
||
|
val lowestIndexFirst: Policy = (valids, idle) =>
|
||
|
valids.scanLeft(Bool(true))(_ && !_).init
|
||
|
|
||
|
def apply[T <: Data](policy: Policy)(sink: IrrevocableIO[T], sources: (UInt, IrrevocableIO[T])*) {
|
||
|
require (sources.size >= 1)
|
||
|
|
||
|
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)
|
||
|
|
||
|
// Who wants access to the sink?
|
||
|
val valids = sourcesIn.map(_.valid)
|
||
|
// Arbitrate amongst the requests
|
||
|
val readys = Vec(policy(valids, idle))
|
||
|
// Which request wins arbitration?
|
||
|
val winners = Vec((readys zip valids) map { case (r,v) => r&&v })
|
||
|
|
||
|
// Confirm the policy works properly
|
||
|
require (readys.size == valids.size)
|
||
|
// Never two winners
|
||
|
val prefixOR = winners.scanLeft(Bool(false))(_||_).init
|
||
|
assert((prefixOR zip winners) map { case (p,w) => !p || !w } reduce {_ && _})
|
||
|
// If there was any request, there is a winner
|
||
|
assert (!valids.reduce(_||_) || winners.reduce(_||_))
|
||
|
|
||
|
// Track remaining beats
|
||
|
val maskedBeats = (winners zip beatsIn) map { case (w,b) => Mux(w, b, UInt(0)) }
|
||
|
val initBeats = maskedBeats.reduce(_ | _) // no winner => 0 beats
|
||
|
val todoBeats = Mux(idle, initBeats, beatsLeft)
|
||
|
beatsLeft := todoBeats - sink.fire()
|
||
|
assert (!sink.fire() || todoBeats =/= UInt(0)) // underflow is impoosible
|
||
|
|
||
|
// The one-hot source granted access in the previous cycle
|
||
|
val state = RegInit(Vec.fill(sources.size)(Bool(false)))
|
||
|
val muxState = Mux(idle, winners, state)
|
||
|
state := muxState
|
||
|
|
||
|
val ones = Vec.fill(sources.size)(Bool(true))
|
||
|
val picked = Mux(idle, ones, state)
|
||
|
sink.valid := Mux1H(picked, valids)
|
||
|
|
||
|
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.bits := Mux1H(muxState, sourcesIn.map(_.bits))
|
||
|
}
|
||
|
}
|