了解spinal.lib.OHMasking.roundRobin
class RoundRobin(n: Int) extends Component{
val io = new Bundle{
val req = in Bits(4 bit)
val pio = in Bits(4 bit)
val sel = out Bits(4 bit)
}
io.sel := OHMasking.roundRobin(io.req, io.pio)
}
其中 req 为请求,可以是并行的几个同时来, io.pio为优先级选中bit, 只有1bit 有效,全0或者多bit就无意义。从pio第一个比特开始查找高bit为第一个出现的位置作为输出。
所以不同的pio输入会实现不同的调度策略。但是在pio固定的前提下,从低到高环装查询。也就是所谓的RoundRobin调度。
轮询调度
pio一般选择轮询策略,比如7bit的req, pio 从 0b0000001 循环左移即可。
时序仿真:
权重轮询调度
在一个调度周期内按权重将令牌分给调度器。权重体现在一个大的调度周期内,并不是说单次调度的权重。
比如20个req,4个通道A,B,C,D,安全中分配
A: 10个令牌
B: 5 个令牌
C: 3个令牌
D: 2个令牌
令牌重置条件.
准则:
1: 首先保证带宽不浪费(不能站着茅坑不拉屎)
2: 其次按权重调度
val tokenReset = !(request & tokens).orR
具体到实际情况就分为以下两种情况:
- 低权重通道有请求,但没令牌,高权重通道有令牌,但没请求,这是需要令牌重置。
- 所有通道令牌都消耗完,重置
优先级抢占调度
- 按优先级通道无脑抢占,导致低优先级饿死
- 按优先级通道抢占n次(可配)后释放一次给低优先级,低优先级调度一次后复位高优先级抢占令牌(这样可以保证高优先级不会连续抢占地通道优先级)(权重调度的特殊情况)
- 一般化的多通道优先级抢占调度 相当于带权重的令牌调度。
优先级和轮询调度结合
round-ribon算法的好处是所有总线主设备得到总线的机会均等,缺点是对于及时得到总线主设备需要排队,影响系统效率。
而多久优先级算法的有点在于他能够保证优先级设备快速访问总线,但是会造成低优先级设备一直得不到总线的控制权。
为了克服以上两种算法的缺点可以采用两种算法结合,,两组设备内使用RoundRobin算法。组件使用优先级。这样既能保证主设备1,2能够及时得到总线,又能保证低优先级的设备不会失去访问机会。
http://www.doc88.com/p-2661096550414.html
总线仲裁
一般总线分为前向命令通道,包括读命令,写命令, 另外还有后向回读数据通道。
前向命令通道通过roundRobin 给出仲裁, 选择其中的master发起命令,并且要在ID fifo中记录到底是哪个命令。到读通道返回的时候把对于master的rdvalid要置位,其他master rdvalid 置无效
roundRobin 源码
def roundRobin[T <: Data](requests : T,ohPriority : T) : T = {
val width = requests.getBitsWidth
val uRequests = requests.asBits.asUInt
val uGranted = ohPriority.asBits.asUInt
val doubleRequests = uRequests @@ uRequests
val doubleGrant = doubleRequests & ~(doubleRequests-uGranted)
val masked = doubleGrant(width,width bits) | doubleGrant(0,width bits)
val ret = cloneOf(requests)
ret.assignFromBits(masked.asBits)
ret
}
RR(roundRobin)算法注解:
val width = io.request.getBitsWidth
val uRequests = io.request.asBits.asUInt
val uGranted = io.ohpriorty.asBits.asUInt
val doubleRequests = uRequests @@ uRequests //向上copy 复制,保证低位也能出现在高位置
val doubleReqCompPrio = (doubleRequests-uGranted) // 相减,req 和 pio 位置重合,则减掉,否则向上借位
val reverserDoubleReqCP = ~ doubleReqCompPrio // bit 翻转
val doubleGrant = doubleRequests & reverserDoubleReqCP //相与
val masked = doubleGrant(width,width bits) | doubleGrant(0,width bits) // 上下两半合并,使得借位的位置都回到n比特内