risc-v中文社区

 找回密码
 立即注册
查看: 1037|回复: 1

[原创] 仲裁器Arbiter(3)

[复制链接]

347

主题

564

帖子

2237

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2237
发表于 2021-9-12 23:40:26 | 显示全部楼层 |阅读模式
手写一个固定优先级仲裁器,将将源代码逐行注释说明(注释中逻辑值0,false,false.B都是一个意思,1,true,true.B也都是一个意思,不要追究语法了):

import chisel3._
import chisel3.util._
class JArbiterIO[T <: Data](private val gen:T,val n:Int) extends Bundle {
  val enq = Flipped(Vec(n,Decoupled(gen)))
  val deq = Decoupled(gen)
  val chosen = Output(UInt(log2Ceil(n).W)) //enq是Vec集合类型,n个元素需要多少bit才能表示这个数
}
//选择哪个producer  最后一个producer没有包含在内(why?) 将返回Seq序号0始终设置为true.B
private object JAribiterCtrl {
  def apply(requests:Seq[Bool]): Seq[Bool] = requests.length match {
    case 0 => Seq()
    case 1 => Seq(true.B)
    case _ => true.B +: requests.tail.init.scanLeft(requests.head)(_ || _).map(!_)  //+: 是中缀操作符,右边的操作数是调用方法的对象 true.B放在前面
      //SeqLike类中有:+和+:,其中:+是普通操作方法,将右加到左的尾部,+:则将左加到右的前部
    //总结:最开始添true.B,去掉last元素之后,只要某位置出现true.B,则从它开始包括它在内返回的Seq中都是false.B,
    //      如果是最后一个元素不管是true.B还是false.B,则最终返回的Seq全部都是本总结前面所述结果(因为最后一个元素被tail.init丢弃了)

  }
}
class JArbiter[T <: Data](gen:T,n:Int) extends Module {
  val io = IO(new JArbiterIO(gen,n))
  //先要赋默认值
  io.deq.bits := io.enq(n-1).bits //最后一个enq的数据
  io.chosen := (n-1).asUInt() //最大序号
  for(i <- (n-2) to 0 by -1) { //n=3 n=2 n=1 n=0  (n=3时循环2次,n=2时循环1次,n=1或0时不循环) 也就是说(n-2) to 0 by -1也是将last enq去掉了
    when(io.enq(i).valid) { //只要某个输入的valid有效
      io.deq.bits := io.enq(i).bits //仲裁器的输出数据为它对应的数据 如果有多个valid,则根据语法,最后(序号小)一个的赋值将会是仲裁器数据输出
      io.chosen := i.asUInt()
    }
  }
  //如果只有一个in,则grant(0)=true.B
  //如果只有二个in,grant(0)=true.B,grant(1)=io.enq(0).valid的值取反
  //如果有三个in,grant(0)=true.B,grant(1)=io.enq(0).valid的值取反,grant(2)=io.enq(1).valid的值取反
  val grant = JAribiterCtrl(io.enq.map(_.valid)) //所有enq的valid
  for((enq,g) <- io.enq zip grant) { //Lit(1,2,3) zip (4,5)==>List((1,4),(2,5))
    enq.ready := g && io.deq.ready //总结:某个producer发出了valid则小于它序号的所有producer的ready都将ready=1
    //只要有io.deq.ready,那么第0序号的producer的ready肯定会true,如果还有其它序号producer的valid=true.B(多个producer时,先是取最小序号的producer,暂叫producerA),
    //那么producerA对应序号之前grant成员会是true.B,包括本producerA以及本producerA序号之后都是false.B
    //如果只有二个producer,当producer(1)valid=1而producer(0)valid=0时,grant(0)=true.B,grant(1)=其实就是producer(0)的valid值取反即=1
    //如果有三个producer,当producer(2)valid=1时,grant(0)=true.B,grant(1)=true.B(其实就是producer(0)的valid值取反),grant(2)=true.B(其实就是producer(1)的valid值取反)
    //如果只有二个producer,当producer(0)valid=1,grant(0)=true.B,grant(1)=false.B
    //如果有三个producer,当producer(1)valid=1时,grant(0)=true.B,grant(1)=true.B,grant(2)=false.B
  }
  //最后一个producer的valid=1即io.enq.last.valid=1 不管grantlast如何取值,最终 io.deq.valid:=1,但分析分析并且分析对应的数据输出
  //  如果grant.last=1,说明除了最后一个producer之外,其它所有producer的valid都是0,最终 io.deq.valid:=1,输出数据也是最后一个producer的数据
  //  如果grant.last=0,说明倒数第二个或倒数第三/第四等producer的valid总有一个或多个=1,所以io.deq.valid=1,从逻辑角度来看下游收到valid也没有错,此时要分析上面数据是否对应(最小序号的producer的数据)
  //最后一个producer的valid=0即io.enq.last.valid=0 则
  //  如果grant.last=1,说明除了最后一个producer之外,其它所有producer的valid都是0,当然!grant.last=false,最终io.deq.valid=false
  //  如果grant.last=0,说明倒数第二个或倒数第三/第四等producer的valid总有一个或多个=1,所以io.deq.valid=1,从逻辑角度来看下游收到valid也没有错,此时要分析上面数据是否对应(最小序号的producer的数据)
  io.deq.valid := !grant.last || io.enq.last.valid
  //总结:当有多个有效producer时,只有序号最小的producer的数据才能输出
}

回复

使用道具 举报

347

主题

564

帖子

2237

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2237
 楼主| 发表于 2021-9-12 23:46:35 | 显示全部楼层
class MyArbiterTester(m:JArbiter[UInt]) 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 {
  "JArbiter" should "pass" in {
    iotesters.Driver(()=>new JArbiter(UInt(8.W),2))(t => new MyArbiterTester(t))
  }
}
测试打印如下:
[info] [0.003] 启动:
[info] [0.005]         enq(0).ready=0, enq(1).ready=0
[info] [0.005]         enq(0).valid=0, enq(1).ready=0
[info] [0.006] producer1有效:
[info] [0.007]         enq(0).ready=1, enq(1).ready=1
[info] [0.007] deq.valid=1,deq.bits=17
[info] [0.007] producer1和2都有效:
[info] [0.008]         enq(0).ready=1, enq(1).ready=0
[info] [0.009] deq.valid=1,deq.bits=18
[info] [0.009] producer0有效:
[info] [0.010]         enq(0).ready=1, enq(1).ready=0
[info] [0.011] deq.valid=1,deq.bits=18
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



Archiver|手机版|小黑屋|risc-v中文社区

GMT+8, 2024-5-3 04:16 , Processed in 0.018996 second(s), 17 queries .

risc-v中文社区论坛 官方网站

Copyright © 2018-2021, risc-v open source

快速回复 返回顶部 返回列表