目录
AXI PIPELINE设计
简介
在做axi总线开发的时候,主从机之间的一些控制信号需要经过多重逻辑处理,往往这些关键信号需要都是双向握手,无法直接插入寄存器,否则就会引起握手信号时序延迟,导致数据丢失。
本章重点讨论了如何在axi总线上增加pipeline,使得AXI总线时序性能得到提升的同时也满足了axi的控制协议对时序的要求
在数据和valid路径增加pipeline
增加pipeline存在的问题
若主机在数据和valid直接增加pipeline延迟会导致,从机端接收这两个信号的时候延迟一拍,主机的ready信号正常情况下会这么设计:
If(up_valid) dn_ready=1;
Else ds_ready=0;
若valid延迟一拍,ds_ready也会延迟,这样会导致主机发送了两个cycle的valid信号,从机误以为主机操作了两次总线。
改进措施
在主机测增加数据锁存,利用up_ready信号锁存住数据和有效信号,通过逻辑:
us_ready <= ds_ready or not ds_valid;
在ds_ready为0的时候即使锁住主机的信号
整体代码如下:
entity pipe_demo_stage is
port(
clk : in std_logic;
-- upstream interface
us_valid : in std_logic;
us_data : in std_logic_vector(7 downto 0);
us_ready : out std_logic;
-- downstream interface
ds_valid : out std_logic := '0';
ds_data : out std_logic_vector(7 downto 0);
ds_ready : in std_logic
);
end pipe_demo_stage;
architecture rtl of pipe_demo_stage is
begin
process(clk) is
begin
if rising_edge(clk) then
--accept data if ready is high
if us_ready = '1' then
ds_valid <= us_valid;
ds_data <= us_data;
end if;
end if;
end process;
--ready signal with registered ready or primary data register is not valid
us_ready <= ds_ready or not ds_valid;
end rtl;
在ready通路增加pipeline
存在问题
若基于以上的电路,在ready上增加pipeline,会导致主机接收的ready信号延迟一拍,导致数据丢失。
解决方案
在以上的电路基础上再增加一级锁存,来锁住丢失的数据
增加了2-1的mux,来选择哪一个锁存器的数据输出,当ds_rdy为1时,选择第一级寄存器,当ds_rdy为0时,将主机多发出的数据存入第二级寄存器,然后送给从机。
源代码:
entity pipe_demo_stage_reg_ready is
port(
clk : in std_logic;
-- upstream interface
us_valid : in std_logic;
us_data : in std_logic_vector(7 downto 0);
us_ready : out std_logic;
-- downstream interface
ds_valid : out std_logic := '0';
ds_data : out std_logic_vector(7 downto 0);
ds_ready : in std_logic
);
end pipe_demo_stage_reg_ready;
architecture rtl of pipe_demo_stage_reg_ready is
-- expansion registers
signal expansion_data_reg : std_logic_vector(7 downto 0);
signal expansion_valid_reg : std_logic := '0';
-- standard registers
signal primary_data_reg : std_logic_vector(7 downto 0);
signal primary_valid_reg : std_logic := '0';
begin
process(clk) is
begin
if rising_edge(clk) then
--accept data if ready is high
if us_ready = '1' then
primary_valid_reg <= us_valid;
primary_data_reg <= us_data;
-- when ds is not ready, accept data into expansion reg until it is valid
if ds_ready = '0' then
expansion_valid_reg <= primary_valid_reg;
expansion_data_reg <= primary_data_reg;
end if;
end if;
-- when ds becomes ready the expansion reg data is accepted and we must clear the valid register
if ds_ready = '1' then
expansion_valid_reg <= '0';
end if;
end if;
end process;
--ready as long as there is nothing in the expansion register
us_ready <= not expansion_valid_reg;
--selecting the expansion register if it has valid data
ds_valid <= expansion_valid_reg or primary_valid_reg;
ds_data <= expansion_data_reg when expansion_valid_reg else primary_data_reg;
end rtl;