仲裁器是硬件设计中非常常用的块。
我想我可以在家里找到仲裁者的最好例子。当我的两个孩子十几岁时,我只有一辆车。在周五和周六晚上,通常会因为谁可以使用汽车而发生冲突。通常,由我来决定(仲裁者)谁得到了这辆车。这不是一件容易的事。(我仍然只有一辆车,正好我的孩子都不是十几岁了,赞美主,他们有自己的车)。
硬件板没有什么不同。至少在两种情况下,多个用户“需要”共享(且有价值且昂贵)的资源:
仲裁者是硬件的一部分,它决定谁可以在任何给定时间使用公共的、有价值的资源。然而,与足球仲裁器不同的是,VHDL 仲裁器永远不会将其中一个设备从“游戏”中移除(好吧......几乎永远不会。在某些情况下,硬件仲裁器会决定一个设备表现不佳并决定将其从“游戏”中移除一个例子是可插拔卡访问公共总线,可以在关键时刻拔掉,如果仲裁器没有识别出故障,总线可能会卡在 - 现在丢失的 - 设备上)。
仲裁器从其客户端接收两种类型的信号:
我们将分析的第一个仲裁器具有三个请求输入和三个授权输出。它也有一个固定的主人优先权。master 编号越低,其优先级越高。该块也有忙信号。总线仲裁仅在其处于非活动状态时进行。如果总线已经被授权给代理,即使更高优先级的主机请求总线,当前事务也必须在仲裁器将总线授权给另一个主机之前完成。
生成授权信号的逻辑(在进程arbiter_pr上)非常简单。如果第一个主控(主控 0)断言请求,则它被授予授权。只有当主控 1 请求总线而主控 0 不请求总线时,它才会获得授权。只有当主控 2 请求总线并且主控 0 和主控 1 都没有请求总线时,它才会被授予授权。
gnt信号只有在总线不忙时才会改变。进程busy_pr和相关逻辑检测忙信号的下降沿。在 busy 变为低电平后,所有授权信号都被取消断言一个时钟,然后选择下一个总线主机的逻辑被激活。
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity arbiter is
port (
clk : in std_logic;
rst : in std_logic;
-- inputs
req : in std_logic_vector(2 downto 0);
busy : in std_logic;
-- outputs
gnt : out std_logic_vector(2 downto 0)
);
end arbiter;
architecture rtl of arbiter is
signal busy_d : std_logic := '0';
signal busy_fe : std_logic;
begin
busy_pr : process (clk)
begin
if (rising_edge(clk)) then
busy_d <= busy;
end if;
end process busy_pr;
-- Falling edge of busy signal
busy_fe <= '1' when busy = '0' and busy_d = '1' else '0';
arbiter_pr : process (clk, rst)
begin
if (rst = '1') then
gnt <= (others => '0');
elsif (rising_edge(clk)) then
if (busy_fe = '1') then
gnt <= (others => '0');
elsif (busy = '0') then
gnt(0) <= req(0);
gnt(1) <= req(1) and not req(0);
gnt(2) <= req(2) and not (req(0) or req(1));
end if;
end if;
end process arbiter_pr;
end rtl;
gnt信号只有在总线不忙时才会改变。进程busy_pr和相关逻辑检测忙信号的下降沿。在 busy 变为低电平后,所有授权信号都被取消断言一个时钟,然后选择下一个总线主机的逻辑被激活。
复位释放后,没有未完成的请求,因此仲裁器也不会断言任何授权信号。稍后在模拟中,多个主机请求仲裁器的许可(请求已断言)并根据其优先级获得授权。
在 300 到 400ns 之间,主机“1”断言其请求信号。两个时钟周期后,来自主机“0”的请求被置位。因此,即使 master '0' 稍后到达,当仲裁器可以自由分配总线时,它也会将其分配给 master '0'。
请注意,在gnt信号之间始终有一个“休息”时钟。每个主机使用总线四个时钟并放弃总线(这可以在忙信号的持续时间内看到)。
稍后,主机“2”和“0”都请求总线,正如预期的那样,总线被授予主机“0”。
GitHub 上提供了仲裁器“简单实现”、测试平台和 Modelsim 文件的 VHDL 源代码
上述仲裁器的逻辑是固定大小的。通过一些更改,并通过使用不受约束的端口(查看req和gnt端口),我们可以制作一个通用仲裁器,其大小可以在实现时决定。
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity arbiter_unc is
port (
clk : in std_logic;
rst : in std_logic;
-- inputs
req : in std_logic_vector;
busy : in std_logic;
-- outputs
gnt : out std_logic_vector
);
end arbiter_unc;
architecture rtl of arbiter_unc is
signal busy_d : std_logic;
signal busy_fe : std_logic;
begin
busy_pr : process (clk)
begin
if (rising_edge(clk)) then
busy_d <= busy;
end if;
end process busy_pr;
-- Falling edge of busy signal
busy_fe <= '1' when busy = '0' and busy_d = '1' else '0';
arbiter_pr : process (clk)
variable prio_req : std_logic;
begin
if (rising_edge(clk)) then
if (rst = '1') then
gnt <= (others => '0');
else
if (busy_fe = '1') then
gnt <= (others => '0');
elsif (busy = '0') then
gnt(0) <= req(0);
for I in 1 to req'left - 1 loop
prio_req := '0';
for J in 1 to I loop
prio_req := prio_req or req(J - 1);
end loop;
gnt(I) <= req(I) and not prio_req;
end loop;
end if;
end if;
end if;
end process arbiter_pr;
end rtl;
可变大小仲裁器的 Vivado 仿真,实例化为 size = 4
RTL 表示显示了处理越来越多的端口所需的组合复杂性不断增加,并且是使用 Quartus Prime 15.1 生成的。请注意,某些块(如输出 FF)不是单个而是堆叠的原始实例化。如前所述,如果多个主机请求总线,则编号最小的主机将获得gnt(回想一下,在任何给定时间只有一个主机应接收gnt)。这个仲裁器有一个固定的优先级。虽然在某些应用程序中可以使用这样的仲裁器,但最常见的仲裁器类型没有固定的优先级。我将在以后的文章中讨论更复杂的仲裁器(循环法)。
GitHub 上提供了仲裁器“无约束实现”、测试平台和 Modelsim 文件的 VHDL 源代码
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
全部0条评论
快来发表一下你的评论吧 !