joe 发表于 2021-9-10 21:24:01

仲裁器Arbiter(2)

//仲裁器的IO Bundle 用Vec(n,Decoupled(gen)表示有多个producer,Decoupled(gen)表示只有一个consummer,还有一个chosen选择指示索引
class ArbiterIO(private val gen: T, val n: Int) extends Bundle {
// See github.com/freechipsproject/chisel3/issues/765 for why gen is a private val and proposed replacement APIs.

val in= Flipped(Vec(n, Decoupled(gen)))
val out = Decoupled(gen)
val chosen = Output(UInt(log2Ceil(n).W))
}
//检测哪一个producer被访问
private object ArbiterCtrl {
def apply(request: Seq): Seq = request.length match {
    case 0 => Seq() //空
    case 1 => Seq(true.B) //元素个数是1则始终是true.B
    case _ => true.B +: request.tail.init.scanLeft(request.head)(_ || _).map(!_) //从head开始一直扫描到倒数第二个(最后一个不包括在内),在结果的最前面再加一个true.B,也就是说数量不变
        //head是true.B,则scalLeft(head)(_ || _)生成的Seq每个元素都是true.B,再map(!_)则全都是false.B,最终只有加进来的true.B才是true值
        //head是false.B,则scalLeft(head)(_ || _)生成的Seq第一个是false.B,第二个是第二个的值,第三个是前一个与本项的||,总结来说,从哪一个索引项的值为true开始,后面生成的Seq的所有项都是true
        //      当然,再map(!_)之后,从这项开始后面全都是false.B了
        //case _=>这句总结:第一项是true.B,Seq的最后一项不包括在内,Seq中从哪一个项的值为true.B开始(包括它在内),后面所有的项的值在最终生成的Seq中的值都是false.B
}
}
class Arbiter(gen: T, n: Int) extends Module {
val io = IO(new ArbiterIO(gen, n))

io.chosen := (n-1).asUInt //默认选择n-1通道
io.out.bits := io.in(n-1).bits //默认数据为n-1通道的数据
for (i <- n-2 to 0 by -1) { //从n-2,n-3,n-4,...,2,1,0,从大到小
    when (io.in(i).valid) { //只要哪个producer的valid是true.B
      io.chosen := i.asUInt //io.chosen就选择这个索引,如果有多个,则最小序号的有效(因为多次:=,只有最后一个有效)
      io.out.bits := io.in(i).bits //本仲裁器模块的输出数据连到这个序号的producer的数据线(多个producer的valid有效时,最小序号的有效)
    }
}

private val grant = ArbiterCtrl(io.in.map(_.valid))//多个producer,其实也是Seq类型,所以有map处理每个元素(每个元素的类型是DecoupledIO即有valid,ready,bits),
//_.valid 表示每个DecoupledIO的valid信号。所以本句代码的作用是:调用ArbiterCtrl的apply方法,参数是仲裁器的多个producer的DecoupledIO的valid信号值组成的Seq
for ((in, g) <- io.in zip grant) //所有的producer即Vec] zip grant
    in.ready := g && io.out.ready //producer的ready信号 := 这个producer的valid && 下游发过来的ready信号(表示数据接收已准备好) 造成有可能没仲裁到它但在处理其它producer很长时间???
io.out.valid := !grant.last || io.in.last.valid //模块输出valid := 所有producer的valid组成的Seq的最小序号的值取反 || 各个producer组成的Vec的最小序号producer的valid
//也就是说如果最小序号producer的valid是无效的,模块输出的valid就指数据输出有效
//如果序号最小的producer的valid有效则模块输出的valid也指示有效
}

joe 发表于 2021-9-10 21:26:04

测试代码:
class MyArbiterTester(m:MyArbiter) extends PeekPokeTester(m) {
poke(m.io.enq(0).valid,false)
poke(m.io.enq(1).valid,false)
poke(m.io.deq.ready,false)
println(s"启动:")
println(s"\tenq(0).ready=${peek(m.io.enq(0).ready)}, enq(1).ready=${peek(m.io.enq(1).ready)}")
println(s"\tenq(0).valid=${peek(m.io.enq(0).valid)}, enq(1).ready=${peek(m.io.enq(1).valid)}")
poke(m.io.enq(0).bits,18) //producer0的数据先输入在此,不变动
poke(m.io.enq(1).valid,true) //producer1的valid有效
poke(m.io.enq(1).bits,17)
poke(m.io.deq.ready,true)//下游发出ready
println(s"producer1有效:")
println(s"\tenq(0).ready=${peek(m.io.enq(0).ready)}, enq(1).ready=${peek(m.io.enq(1).ready)}")
println(s"deq.valid=${peek(m.io.deq.valid)},deq.bits=${peek(m.io.deq.bits)}")
poke(m.io.enq(0).valid,true)

println(s"producer1和2都有效:")
println(s"\tenq(0).ready=${peek(m.io.enq(0).ready)}, enq(1).ready=${peek(m.io.enq(1).ready)}")
println(s"deq.valid=${peek(m.io.deq.valid)},deq.bits=${peek(m.io.deq.bits)}")
poke(m.io.enq(1).valid,false)
println(s"producer0有效:")
println(s"\tenq(0).ready=${peek(m.io.enq(0).ready)}, enq(1).ready=${peek(m.io.enq(1).ready)}")
println(s"deq.valid=${peek(m.io.deq.valid)},deq.bits=${peek(m.io.deq.bits)}")

}
class DownTickerSpec extends ChiselFlatSpec {
"MyArbiter" should "pass" in {
    iotesters.Driver(()=>new MyArbiter(UInt(8.W),2))(t => new MyArbiterTester(t))
}
}
显示如下:
启动:
        enq(0).ready=0, enq(1).ready=0
        enq(0).valid=0, enq(1).ready=0
producer1有效:
        enq(0).ready=1, enq(1).ready=1
deq.valid=1,deq.bits=17
producer1和2都有效:
        enq(0).ready=1, enq(1).ready=0
deq.valid=1,deq.bits=18
producer0有效:
        enq(0).ready=1, enq(1).ready=0
deq.valid=1,deq.bits=18
页: [1]
查看完整版本: 仲裁器Arbiter(2)