今天看到了一种很有意思的固定优先级仲裁器https://blog.youkuaiyun.com/weixin_43698385/article/details/125983047
module fixed_arb_2(request,grant);
input [3:0] request;
output [3:0] grant;
assign {grant[0],grant[1],grant[2],grant[3]}=
{1'b1,request[0],request[1],request[2],request[3]} &
~({1'b1,request[0],request[1],request[2],request[3]}-1'b1);
endmodule
这个仲裁器通过加法实现
按照优先级为A<B<C<D,考虑一下是怎么实现的
步骤总得来说就是减1,取反,按位相与
对于输入,假设request
为4'b1001
,则对它先减1得到4'b1000
对它再取反得到4'b0111
,
最后与request
按位相与得到grant
即4'b0001
,也就是最后一位的设备获得授权。那么具体是什么原理呢?
对于按位相与操作来说,如果一个值和经过变化再与自身相与就会得到0,如果变化了两次就要看它原来是1还是0.
而在减一的步骤中,它的目的是为了找到请求信号中最低位的1(即优先级最高的请求)。request
中优先级最高的1位(或2位)发生了一次改变
而取反的步骤中,所有的位都发生了一次改变,那就是说减一的步骤改变的1位(或2位)发生了两次改变,而其他的位都只发生了一次改变。
相与之后发生两次改变的位还保持原来的值不变,而改变一次的位就变成0。所以到这里只有优先级最高的1位(或2位)能够保留原来的值。
如果request
请求的是最低位,那么说明它原来就为1,最后也就只剩它还为1,即grant=4'b0001
如果request
请求的不是最低位,那么最低位原来为0,grant
中最低位也为0,而请求的优先级最高的那位则在变化两次后保持为1。
在进行减法操作时,如果请求信号的所有位都是0(即没有任何请求),那么加上1后,结果不会出现负数或不正确的状态。所以在最前面加一位1,这样可以避免在后续运算中出现意外的逻辑错误。
而代码的逻辑是通过构造5位信号来处理请求的优先级,但最终赋值给4位的grant
信号时,只会使用右侧信号的低4位,因此,虽然存在位宽不匹配的情况,但Verilog会自动处理并确保赋值的正确性。