看看下面的arbiter.v代码:
有人告诉我想到 rr_arbiter 是因为它是一个简化版 ripple-borrow circuit环绕起来。
'base' is a one hot signal indicating the first request that should be considered for a grant.
嗯?你们知道如何生成“基本”输入信号吗?
Notice the subtraction. The borrow logic causes it to search to find the next set bit.
为什么~(double_req-base)?
module arbiter (
req, grant, base
);
parameter WIDTH = 16;
input [WIDTH-1:0] req;
output [WIDTH-1:0] grant;
input [WIDTH-1:0] base;
wire [2*WIDTH-1:0] double_req = {req,req};
wire [2*WIDTH-1:0] double_grant = double_req & ~(double_req-base);
assign grant = double_grant[WIDTH-1:0] | double_grant[2*WIDTH-1:WIDTH];
endmodule
最佳答案
编辑:正如有人指出的,我最初只指出如何设置输入信号并给出了两种特殊情况作为示例。让我尝试解释一下它是如何工作的。你的问题是一个好的开始:
why ~(double_req-base) ?
正如有人向您指出的那样,这是基于 ripple borrow subtractor 的原则。 。当你用一个数字减去另一个数字时,无论你使用什么数字系统,你都会从最低的顺序开始,并尝试从相同的顺序中减去两个数字。在二进制示例中,这将如下所示:
1011 = 11
0010 - = 2 -
────── ────
1001 = 9
如您所见,1 - 1
有效并产生 0
。但是,如果不可能,您可以借用更高的订单号。 This image显示了十进制系统中的一个简单示例。十进制系统中的一个示例可能是:
1001 = 01(10)1 = 9
0010 - = 00 1 0 - = 2 -
────── ───────── ───
0111 = 01 1 1 = 7
<小时/>
自 0 - 1
在第二个位置是不可能的,我们从第四个位置取1,将第三个位置设置为1
并将第二个位置设置为 10
(因此,十进制为 2)。这与example in the decimal system I posted before非常相似。 .
对于仲裁者来说很重要:原始数字的下一个 1 ( req
),从 base
的位置看到,将被设置为零。基本位置和 0
之间的所有数字将被设置为1
。将减法结果取反后,只有这个位置是1
从底座看去。
但是,阶次低于基数的数字仍然可能是 1
用这种技术。因此,我们将原始数字与您计算出的数字 ( double_req & ~(double_req-base)
) 连接起来。这确保了可能 1
位于低于 base
的位置被淘汰。
最后,它加倍的事实确保了它不会耗尽可借的头寸。如果需要从这些“第二个”双倍 block 借用,则析取 ( double_grant[WIDTH-1:0] | double_grant[2*WIDTH-1:WIDTH]
) 确保它返回正确的索引。我在下面的示例中添加了一个示例。
原帖
您可以解读base
作为 req
中的起始索引。这是代码将考虑进行仲裁的第一个位。您应该将此值设置为 last_arbitrated_position + 1
.
看一下我在下面创建的 4 位(伪代码)示例。让我们取一些任意数字:
req = 4'b1101 // Your vector from which one position should be arbitrated
base = 4'b0010 // The second position is the first position to consider
现在,从 arbiter.v
,如下:
double_req = 1101 1101
double_grant = 1101 1101 & ~(1101 1011) = 1101 1101 & 0010 0100 = 0000 0100
在最后的步骤中,arbiter.v
然后实际分配应该授予的位置:
grant = 0100 | 0000 = 0100
这是正确的,因为我们将第二个位置设置为基础,下一个有效位置是第三个。另一个例子,其中基数是在 req
中也有效的位置。 ,是:
req = 4'b1111
base = 4'b0010
double_req = 1111 1111
double_grant = 1111 1111 & ~(1111 1101) = 1111 1111 & 0000 0010 = 0000 0010
grant = 0010 | 0000
这又是正确的,因为在本例中我们定义了第一个可以仲裁的位置是第二个位置,并且这个位置确实有效。
您发布的代码示例还负责环绕最高有效位。这意味着,如果您设置了基数,但没有大于该基数的有效位置,它将回绕并从最低有效位开始仲裁。这种情况的一个例子是:
req = 4'b0010
base = 4'b0100
double_req = 0010 0010
double_grant = 0010 0010 & ~(1110 0001) = 0010 0010 & 0001 1110 = 0010 0000
grant = 0000 | 0010
关于verilog - 了解简单的循环仲裁器 verilog 代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55015328/