文章目录
基本概念
简介
AXI4协议是AMBA协议(Advanced Microcontroller Bus Architecture)的一种,是由ARM和XILINX共同制定的最新一代用于SoC内IP 互联的规范。
AMBA协议家族树
AXI4协议包含三种AXI4接口,
- AXI4(Memory-Mapped):基于地址映射的传输接口,允许突发长度可变的数据传输(最大突发长度为256),可用于实现高性能的数据传输;
- AXI4-Lite:基于地址映射的轻量型传输接口,突发长度为1,可用于访问控制寄存器、连接低俗外设;
- AXI4-Stream:基于数据流的传输接口,突发长度无限制,可用于高速数流的传输。
AXI4和AXI4-Lite接口包含5个通道,为读地址通道(AR)、写地址通道(AW)、读数据通道®、写数据通道(W)和写响应通道(B),如图 2、图 3所示。AXI4协议支持多重传输、读/写并发传输等传输方式,所支持的最大突发长度为256,AXI-Lite支持的最大突发长度为1。
读通道结构
写通道结构
信号接口定义
读/写传输
AXI4总线中的主设备和从设备通过VALID信号和READY信号双向握手机制实现数据传输,主设备通过VALID 信号表示是否存在有效数据或控制信号在通道上,从设备通过READY 信号表示是否可以接受通道上的数据,在读/写数据通道上都含有LAST 信号来表示当前传输数据是否为读/写突发传输操作中的最后一个。
读时序
当主设备向从设备发出读请求时,主设备发送突发传输操作的起始地址ARADDR和读地址有效信号ARVALID,同时发送控制信号确定传输的类型、数据长度、数据位宽等。从设备提供读地址准备信号 ARREADY表示接收读地址及其控制信号,根据收到的读地址及其控制信号,然后向主设备返回相应的读数据RDATA和读数据有效信号RVALID,主设备提供读准备信号RREADY表示是否准备接收读数据和响应信号。
AXI 总线的读突发传输时序
根据起始地址和控制信号,主设备从该次突发传输中读到 4个数据,当传输的为最后一个时,最户读数据RLAST为高电平,同时表示该次突发传输结束,可以准备下一次传输
AXI总线的交错读突发传输时序
写时序
当主设备向从设备发出写请求时,主设备发送写突发传输操作的起始地址AWADDR 和写地址有效信号AWVALID,同时发送控制信号确定传输的类型、数据长度、数据位宽等。从设备提供写地址准备信号AWREADY 表示接收写地址及其控制信号,根据收到的写地址及其控制信号,同时主设备提供相应的写数据WDATA 和写数据有效信号WVALID,从设备提供写准备信号WREADY表示接收写数据,并返回响应信号给主设备,表示当前写数据传输的完成状态。
AXI总线的写突发传输时序
突发长度、突发大小、突发类型、突发地址
握手过程及读/写操作的依赖关系
AXI 总线的5 个通道是相互独立的,但是都使用有效信号VALID 和准备信号READY 握手来实现数据与控制信号的传输。有效信号VALID 表示发送方传输的数据和控制信号有效,准备信号READY 表示接收方可以接收数据与控制信号,其中数据为读写地址、读写数据或者响应信号,只有当有效信号VALID 与对应的准备信号READY 都为高电平时,传输才能开始。
VALID在READY之前跳转的握手
READY在VALID之前跳转的握手
VALID与READY同时跳转的握手
封装工具生成的IP
AXI lite
VHDL代码
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity led_control_s_axi is
generic (
C_S_AXI_DATA_WIDTH : integer := 32;
C_S_AXI_ADDR_WIDTH : integer := 4
);
port (
---------------------------------------------------
-- 用户端口
---------------------------------------------------
led_flash_en : out std_logic;
led_flash_time : out std_logic_vector(31 downto 0);
test : out std_logic_vector(127 downto 0);
---------------------------------------------------
-- Axi Slave Bus Interface
---------------------------------------------------
S_AXI_ACLK : in std_logic;
S_AXI_ARESETN : in std_logic;
S_AXI_AWADDR : in std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
S_AXI_AWPROT : in std_logic_vector(2 downto 0);
S_AXI_AWVALID : in std_logic;
S_AXI_AWREADY : out std_logic;
S_AXI_WDATA : in std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
S_AXI_WSTRB : in std_logic_vector((C_S_AXI_DATA_WIDTH/8)-1 downto 0);
S_AXI_WVALID : in std_logic;
S_AXI_WREADY : out std_logic;
S_AXI_BRESP : out std_logic_vector(1 downto 0);
S_AXI_BVALID : out std_logic;
S_AXI_BREADY : in std_logic;
S_AXI_ARADDR : in std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
S_AXI_ARPROT : in std_logic_vector(2 downto 0);
S_AXI_ARVALID : in std_logic;
S_AXI_ARREADY : out std_logic;
S_AXI_RDATA : out std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
S_AXI_RRESP : out std_logic_vector(1 downto 0);
S_AXI_RVALID : out std_logic;
S_AXI_RREADY : in std_logic
);
end led_control_s_axi;
architecture arch_imp of led_control_s_axi is
-------------------------------------------------------------------------------
-- 常量声明
-------------------------------------------------------------------------------
-- local parameter for addressing 32 bit / 64 bit C_S_AXI_DATA_WIDTH
-- ADDR_LSB is used for addressing 32/64 bit registers/memories
-- ADDR_LSB = 2 for 32 bits (n downto 2)
-- ADDR_LSB = 3 for 64 bits (n downto 3)
constant ADDR_LSB : integer := (C_S_AXI_DATA_WIDTH/32)+ 1;
constant OPT_MEM_ADDR_BITS : integer := 1;
-------------------------------------------------------------------------------
-- 信号声明
-------------------------------------------------------------------------------
---- AXI4LITE signals
signal axi_awaddr : std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
signal axi_awready : std_logic;
signal axi_wready : std_logic;
signal axi_bresp : std_logic_vector(1 downto 0);
signal axi_bvalid : std_logic;
signal axi_araddr : std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
signal axi_arready : std_logic;
signal axi_rdata : std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
signal axi_rresp : std_logic_vector(1 downto 0);
signal axi_rvalid : std_logic;
---- Signals for user logic register space example
signal slv_reg0 : std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
signal slv_reg1 : std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
signal slv_reg2 : std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
signal slv_reg3 : std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
signal slv_reg_rden : std_logic;
signal slv_reg_wren : std_logic;
signal reg_data_out : std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
signal byte_index : integer;
signal aw_en : std_logic;
begin
-- I/O Connections assignments
S_AXI_AWREADY <= axi_awready;
S_AXI_WREADY <= axi_wready;
S_AXI_BRESP <= axi_bresp;
S_AXI_BVALID <= axi_bvalid;
S_AXI_ARREADY <= axi_arready;
S_AXI_RDATA <= axi_rdata;
S_AXI_RRESP <= axi_rresp;
S_AXI_RVALID <= axi_rvalid;
-------------------------------------------------------
-- Implement axi_awready generation
-- axi_awready is asserted for one S_AXI_ACLK clock cycle when both S_AXI_AWVALID and S_AXI_WVALID are asserted.axi_awready is de-asserted when reset is low.
-----------------------------------
-- Implement axi_awaddr latching
-- This process is used to latch the address when both S_AXI_AWVALID and S_AXI_WVALID are valid.
-------------------------------------------------------
process (S_AXI_ACLK)
begin
if rising_edge(S_AXI_ACLK) then
if S_AXI_ARESETN = '0' then
axi_awready <= '0';
aw_en <= '1';
axi_awaddr <= (others => '0');
else
if (axi_awready = '0' and S_AXI_AWVALID = '1' and S_AXI_WVALID = '1' and aw_en = '1') then
-- slave is ready to accept write address when there is a valid write address and write data on the write address and data bus.
-- This design expects no outstanding transactions.
axi_awready <= '1';
aw_en <= '0';
axi_awaddr <= S_AXI_AWADDR;
elsif (S_AXI_BREADY = '1' and axi_bvalid = '1') then
axi_awready <= '0';
aw_en <= '1';
else
axi_awready <= '0';
end if;
end if;
end if;
end process;
-- Implement axi_wready generation
-- axi_wready is asserted for one S_AXI_ACLK clock cycle when both S_AXI_AWVALID and S_AXI_WVALID are asserted. axi_wready is de-asserted when reset is low.
process (S_AXI_ACLK)
begin
if rising_edge(S_AXI_ACLK) then
if S_AXI_ARESETN = '0' then
axi_wready <= '0';
else
if (axi_wready = '0' and S_AXI_WVALID = '1' and S_AXI_AWVALID = '1' and aw_en = '1') then
-- slave is ready to accept write data when there is a valid write address and write data on the write address and data bus.
-- This design expects no outstanding transactions.
axi_wready <= '1';
else
axi_wready <= '0';
end if;
end if;
end if;
end process;
-- Implement write response logic generation
-- The write response and response valid signals are asserted by the slave when axi_wready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted.
-- This marks the acceptance of address and indicates the status of write transaction.
process (S_AXI_ACLK)
begin
if rising_edge(S_AXI_ACLK) then
if S_AXI_ARESETN = '0' then
axi_bvalid <= '0';
axi_bresp <= "00"; --need to work more on the responses
else
if (axi_awready = '1' and S_AXI_AWVALID = '1' and axi_wready = '1' and S_AXI_WVALID = '1' and axi_bvalid = '0' ) then
axi_bvalid <= '1';
axi_bresp <= "00";
elsif (S_AXI_BREADY = '1' and axi_bvalid = '1') then --check if bready is asserted while bvalid is high)
axi_bvalid <= '0'; -- (there is a possibility that bready is always asserted high)
end if;
end if;
end if;
end process;
-- Implement axi_arready generation
-- axi_arready is asserted for one S_AXI_ACLK clock cycle when S_AXI_ARVALID is asserted. axi_awready is de-asserted when reset (active low) is asserted.
-- The read address is also latched when S_AXI_ARVALID is asserted. axi_araddr is reset to zero on reset assertion
process (S_AXI_ACLK)
begin
if rising_edge(S_AXI_ACLK) then
if S_AXI_ARESETN = '0' then
axi_arready <= '0';
axi_araddr <= (others => '1');
else
if (axi_arready = '0' and S_AXI_ARVALID = '1') then
axi_arready <= '1';
axi_araddr <= S_AXI_ARADDR;
else
axi_arready <= '0';
end if;
end if;
end if;
end process;
-- Implement axi_arvalid generation
-- axi_rvalid is asserted for one S_AXI_ACLK clock cycle when both
-- S_AXI_ARVALID and axi_arready are asserted. The slave registers
-- data are available on the axi_rdata bus at this instance. The
-- assertion of axi_rvalid marks the validity of read data on the
-- bus and axi_rresp indicates the status of read transaction.axi_rvalid
-- is deasserted on reset (active low). axi_rresp and axi_rdata are
-- cleared to zero on reset (active low).
process (S_AXI_ACLK)
begin
if rising_edge(S_AXI_ACLK) then
if S_AXI_ARESETN = '0' then
axi_rvalid <= '0';
axi_rresp <= "00";
else
if (axi_arready = '1' and S_AXI_ARVALID = '1' and axi_rvalid = '0') then
axi_rvalid <= '1';
axi_rresp <= "00"; -- 'OKAY' response
elsif (axi_rvalid = '1' and S_AXI_RREADY = '1') then
axi_rvalid <= '0';
end if;
end if;
end if;
end process;
-- Implement memory mapped register select and write logic generation
-- The write data is accepted and written to memory mapped registers when
-- axi_awready, S_AXI_WVALID, axi_wready and S_AXI_WVALID are asserted.
-- These registers are cleared when reset (active low) is applied.
-- Slave register write enable is asserted when valid address and data are available
-- and the slave is ready to accept the write address and write data.
slv_reg_wren <= axi_wready and S_AXI_WVALID and axi_awready and S_AXI_AWVALID ;
process (S_AXI_ACLK)
variable loc_addr :std_logic_vector(OPT_MEM_ADDR_BITS downto 0);
begin
if rising_edge(S_AXI_ACLK) then
if S_AXI_ARESETN = '0' then
slv_reg0 <= (others => '0');
slv_reg1 <= (others => '0');
slv_reg2 <= (others => '0');
slv_reg3 <= (others => '0');
else
loc_addr := axi_awaddr(ADDR_LSB + OPT_MEM_ADDR_BITS downto ADDR_LSB);
if (slv_reg_wren = '1') then
case loc_addr is
when b"00" =>
for byte_index in 0 to (C_S_AXI_DATA_WIDTH/8-1) loop
if ( S_AXI_WSTRB(byte_index) = '1' ) then
slv_reg0(byte_index*8+7 downto byte_index*8) <= S_AXI_WDATA(byte_index*8+7 downto byte_index*8);
end if;
end loop;
when b"01" =>
for byte_index in 0 to (C_S_AXI_DATA_WIDTH/8-1) loop
if ( S_AXI_WSTRB(byte_index) = '1' ) then
slv_reg1(byte_index*8+7 downto byte_index*8) <= S_AXI_WDATA(byte_index*8+7 downto byte_index*8);
end if;
end loop;
when b"10" =>
for byte_index in 0 to (C_S_AXI_DATA_WIDTH/8-1) loop
if ( S_AXI_WSTRB(byte_index) = '1' ) then
slv_reg2(byte_index*8+7 downto byte_index*8) <= S_AXI_WDATA(byte_index*8+7 downto byte_index*8);
end if;
end loop;
when b"11" =>
for byte_index in 0 to (C_S_AXI_DATA_WIDTH/8-1) loop
if ( S_AXI_WSTRB(byte_index) = '1' ) then
slv_reg3(byte_index*8+7 downto byte_index*8) <= S_AXI_WDATA(byte_index*8+7 downto byte_index*8);
end if;
end loop;
when others =>
slv_reg0 <= slv_reg0;
slv_reg1 <= slv_reg1;
slv_reg2 <= slv_reg2;
slv_reg3 <= slv_reg3;
end case;
end if;
end if;
end if;
end process;
-- Implement memory mapped register select and read logic generation
-- Slave register read enable is asserted when valid address is available
-- and the slave is ready to accept the read address.
slv_reg_rden <= axi_arready and S_AXI_ARVALID and (not axi_rvalid) ;
process (slv_reg0, slv_reg1, slv_reg2, slv_reg3, axi_araddr, S_AXI_ARESETN, slv_reg_rden)
variable loc_addr :std_logic_vector(OPT_MEM_ADDR_BITS downto 0);
begin
-- Address decoding for reading registers
loc_addr := axi_araddr(ADDR_LSB + OPT_MEM_ADDR_BITS downto ADDR_LSB);
case loc_addr is
when b"00" =>
reg_data_out <= slv_reg0;
when b"01" =>
reg_data_out <= slv_reg1;
when b"10" =>
reg_data_out <= slv_reg2;
when b"11" =>
reg_data_out <= slv_reg3;
when others =>
reg_data_out <= (others => '0');
end case;
end process;
-- Output register or memory read data
process( S_AXI_ACLK ) is
begin
if (rising_edge (S_AXI_ACLK)) then
if ( S_AXI_ARESETN = '0' ) then
axi_rdata <= (others => '0');
else
if (slv_reg_rden = '1') then
axi_rdata <= reg_data_out;
end if;
end if;
end if;
end process;
-------------------------------------------------------
-- 用户逻辑
-------------------------------------------------------
led_flash_en <= slv_reg0(0);
led_flash_time <= slv_reg1;
-------------------------------------------------------
-- 观测信号
-------------------------------------------------------
test(3 downto 0) <= axi_awaddr;
test( 4) <= axi_awready;
test( 5) <= axi_wready;
test(7 downto 6) <= axi_bresp;
test( 8) <= axi_bvalid;
test(12 downto 9) <= axi_araddr;
test( 13) <= axi_arready;
test(45 downto 14) <= axi_rdata;
test(47 downto 46) <= axi_rresp;
test(48) <= axi_rvalid;
test(49) <= aw_en;
test(53 downto 50) <= S_AXI_AWADDR;
test(56 downto 54) <= S_AXI_AWPROT;
test(57) <= S_AXI_AWVALID;
test(89 downto 58) <= S_AXI_WDATA;
test(93 downto 90) <= S_AXI_WSTRB;
test( 94) <= S_AXI_WVALID;
test( 95) <= S_AXI_BREADY;
test(99 downto 96) <= S_AXI_ARADDR;
test(102 downto 100) <= S_AXI_ARPROT;
test( 103) <= S_AXI_ARVALID;
test( 104) <= S_AXI_RREADY;
test(127 downto 105) <= (others=>'0');
end arch_imp;
写时序
读时序
AXI full
VHDL代码
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity full_test_S_AXI is
generic (
---------------------------------------------------
-- AXI参数
---------------------------------------------------
C_S_AXI_ID_WIDTH : integer := 1;
C_S_AXI_DATA_WIDTH : integer := 32;
C_S_AXI_ADDR_WIDTH : integer := 6;
C_S_AXI_AWUSER_WIDTH : integer := 1;
C_S_AXI_ARUSER_WIDTH : integer := 1;
C_S_AXI_WUSER_WIDTH : integer := 1;
C_S_AXI_RUSER_WIDTH : integer := 1;
C_S_AXI_BUSER_WIDTH : integer := 1
);
port (
---------------------------------------------------
-- 用户端口
---------------------------------------------------
test : out std_logic_vector(255 downto 0);
---------------------------------------------------
-- AXI FULL 端口
---------------------------------------------------
S_AXI_ACLK : in std_logic;
S_AXI_ARESETN : in std_logic;
S_AXI_AWID : in std_logic_vector(C_S_AXI_ID_WIDTH-1 downto 0);
S_AXI_AWADDR : in std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
S_AXI_AWLEN : in std_logic_vector(7 downto 0);
S_AXI_AWSIZE : in std_logic_vector(2 downto 0);
S_AXI_AWBURST : in std_logic_vector(1 downto 0);
S_AXI_AWLOCK : in std_logic;
S_AXI_AWCACHE : in std_logic_vector(3 downto 0);
S_AXI_AWPROT : in std_logic_vector(2 downto 0);
S_AXI_AWQOS : in std_logic_vector(3 downto 0);
S_AXI_AWREGION : in std_logic_vector(3 downto 0);
S_AXI_AWUSER : in std_logic_vector(C_S_AXI_AWUSER_WIDTH-1 downto 0);
S_AXI_AWVALID : in std_logic;
S_AXI_AWREADY : out std_logic;
S_AXI_WDATA : in std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
S_AXI_WSTRB : in std_logic_vector((C_S_AXI_DATA_WIDTH/8)-1 downto 0);
S_AXI_WLAST : in std_logic;
S_AXI_WUSER : in std_logic_vector(C_S_AXI_WUSER_WIDTH-1 downto 0);
S_AXI_WVALID : in std_logic;
S_AXI_WREADY : out std_logic;
S_AXI_BID : out std_logic_vector(C_S_AXI_ID_WIDTH-1 downto 0);
S_AXI_BRESP : out std_logic_vector(1 downto 0);
S_AXI_BUSER : out std_logic_vector(C_S_AXI_BUSER_WIDTH-1 downto 0);
S_AXI_BVALID : out std_logic;
S_AXI_BREADY : in std_logic;
S_AXI_ARID : in std_logic_vector(C_S_AXI_ID_WIDTH-1 downto 0);
S_AXI_ARADDR : in std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
S_AXI_ARLEN : in std_logic_vector(7 downto 0);
S_AXI_ARSIZE : in std_logic_vector(2 downto 0);
S_AXI_ARBURST : in std_logic_vector(1 downto 0);
S_AXI_ARLOCK : in std_logic;
S_AXI_ARCACHE : in std_logic_vector(3 downto 0);
S_AXI_ARPROT : in std_logic_vector(2 downto 0);
S_AXI_ARQOS : in std_logic_vector(3 downto 0);
S_AXI_ARREGION : in std_logic_vector(3 downto 0);
S_AXI_ARUSER : in std_logic_vector(C_S_AXI_ARUSER_WIDTH-1 downto 0);
S_AXI_ARVALID : in std_logic;
S_AXI_ARREADY : out std_logic;
S_AXI_RID : out std_logic_vector(C_S_AXI_ID_WIDTH-1 downto 0);
S_AXI_RDATA : out std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
S_AXI_RRESP : out std_logic_vector(1 downto 0);
S_AXI_RLAST : out std_logic;
S_AXI_RUSER : out std_logic_vector(C_S_AXI_RUSER_WIDTH-1 downto 0);
S_AXI_RVALID : out std_logic;
S_AXI_RREADY : in std_logic
);
end full_test_S_AXI;
architecture arch_imp of full_test_S_AXI is
-------------------------------------------------------------------------------
-- 常量声明
-------------------------------------------------------------------------------
constant ADDR_LSB : integer := (C_S_AXI_DATA_WIDTH/32)+ 1;
constant OPT_MEM_ADDR_BITS : integer := 3;
constant USER_NUM_MEM : integer := 1;
constant ALL_ZEROS : std_logic_vector (C_S_AXI_ADDR_WIDTH - 1 downto 0) := "000000";
-------------------------------------------------------------------------------
-- 信号声明
-------------------------------------------------------------------------------
---------------------------------------------------
-- AXI4 FULL signals
---------------------------------------------------
signal axi_awaddr : std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
signal axi_awready : std_logic;
signal axi_wready : std_logic;
signal axi_bresp : std_logic_vector(1 downto 0);
signal axi_buser : std_logic_vector(C_S_AXI_BUSER_WIDTH-1 downto 0);
signal axi_bvalid : std_logic;
signal axi_araddr : std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
signal axi_arready : std_logic;
signal axi_rdata : std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
signal axi_rresp : std_logic_vector(1 downto 0);
signal axi_rlast : std_logic;
signal axi_ruser : std_logic_vector(C_S_AXI_RUSER_WIDTH-1 downto 0);
signal axi_rvalid : std_logic;
signal aw_wrap_en : std_logic; -- aw_wrap_en determines wrap boundary and enables wrapping
signal ar_wrap_en : std_logic; -- ar_wrap_en determines wrap boundary and enables wrapping
signal aw_wrap_size : integer;
signal ar_wrap_size : integer;
signal axi_awv_awr_flag : std_logic; -- The axi_awv_awr_flag flag marks the presence of write address valid
signal axi_arv_arr_flag : std_logic; --The axi_arv_arr_flag flag marks the presence of read address valid
signal axi_awlen_cntr : std_logic_vector(7 downto 0); -- The axi_awlen_cntr internal write address counter to keep track of beats in a burst transaction
signal axi_arlen_cntr : std_logic_vector(7 downto 0); --The axi_arlen_cntr internal read address counter to keep track of beats in a burst transaction
signal axi_arburst : std_logic_vector(2-1 downto 0);
signal axi_awburst : std_logic_vector(2-1 downto 0);
signal axi_arlen : std_logic_vector(8-1 downto 0);
signal axi_awlen : std_logic_vector(8-1 downto 0);
------------------------------------------------
---- Signals for user logic memory space example
--------------------------------------------------
type ram_type is array (2**OPT_MEM_ADDR_BITS-1 downto 0) of std_logic_vector (C_S_AXI_DATA_WIDTH-1 downto 0);
signal RAM : ram_type;
signal ram_data_in : std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
signal ram_data_out : std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
signal ram_wren,ram_rden : std_logic;
signal ram_address : std_logic_vector(OPT_MEM_ADDR_BITS downto 0);
begin
-- I/O Connections assignments
S_AXI_AWREADY <= axi_awready;
S_AXI_WREADY <= axi_wready;
S_AXI_BRESP <= axi_bresp;
S_AXI_BUSER <= axi_buser;
S_AXI_BVALID <= axi_bvalid;
S_AXI_ARREADY <= axi_arready;
S_AXI_RDATA <= axi_rdata;
S_AXI_RRESP <= axi_rresp;
S_AXI_RLAST <= axi_rlast;
S_AXI_RUSER <= axi_ruser;
S_AXI_RVALID <= axi_rvalid;
S_AXI_BID <= S_AXI_AWID;
S_AXI_RID <= S_AXI_ARID;
aw_wrap_size <= ((C_S_AXI_DATA_WIDTH)/8 * to_integer(unsigned(axi_awlen)));
ar_wrap_size <= ((C_S_AXI_DATA_WIDTH)/8 * to_integer(unsigned(axi_arlen)));
aw_wrap_en <= '1' when (((axi_awaddr AND std_logic_vector(to_unsigned(aw_wrap_size,C_S_AXI_ADDR_WIDTH))) XOR std_logic_vector(to_unsigned(aw_wrap_size,C_S_AXI_ADDR_WIDTH))) = ALL_ZEROS) else
'0';
ar_wrap_en <= '1' when (((axi_araddr AND std_logic_vector(to_unsigned(ar_wrap_size,C_S_AXI_ADDR_WIDTH))) XOR std_logic_vector(to_unsigned(ar_wrap_size,C_S_AXI_ADDR_WIDTH))) = ALL_ZEROS) else
'0';
process (S_AXI_ACLK)
begin
if rising_edge(S_AXI_ACLK) then
if S_AXI_ARESETN = '0' then
axi_awready <= '0';
axi_awv_awr_flag <= '0';
else
if (axi_awready = '0' and S_AXI_AWVALID = '1' and axi_awv_awr_flag = '0' and axi_arv_arr_flag = '0') then
-- slave is ready to accept an address and associated control signals
axi_awv_awr_flag <= '1'; -- used for generation of bresp() and bvalid
axi_awready <= '1';
elsif (S_AXI_WLAST = '1' and axi_wready = '1') then
-- preparing to accept next address after current write burst tx completion
axi_awv_awr_flag <= '0';
else
axi_awready <= '0';
end if;
end if;
end if;
end process;
process (S_AXI_ACLK)
begin
if rising_edge(S_AXI_ACLK) then
if S_AXI_ARESETN = '0' then
axi_awaddr <= (others => '0');
axi_awburst <= (others => '0');
axi_awlen <= (others => '0');
axi_awlen_cntr <= (others => '0');
else
if (axi_awready = '0' and S_AXI_AWVALID = '1' and axi_awv_awr_flag = '0') then
-- address latching
axi_awaddr <= S_AXI_AWADDR(C_S_AXI_ADDR_WIDTH - 1 downto 0); ---- start address of transfer
axi_awlen_cntr <= (others => '0');
axi_awburst <= S_AXI_AWBURST;
axi_awlen <= S_AXI_AWLEN;
elsif((axi_awlen_cntr <= axi_awlen) and axi_wready = '1' and S_AXI_WVALID = '1') then
axi_awlen_cntr <= std_logic_vector(unsigned(axi_awlen_cntr) + 1);
case (axi_awburst) is
when "00" => -- fixed burst
-- The write address for all the beats in the transaction are fixed
axi_awaddr <= axi_awaddr; ----for awsize = 4 bytes (010)
when "01" => --incremental burst
-- The write address for all the beats in the transaction are increments by awsize
axi_awaddr(C_S_AXI_ADDR_WIDTH - 1 downto ADDR_LSB) <= std_logic_vector (unsigned(axi_awaddr(C_S_AXI_ADDR_WIDTH - 1 downto ADDR_LSB)) + 1);--awaddr aligned to 4 byte boundary
axi_awaddr(ADDR_LSB-1 downto 0) <= (others => '0'); ----for awsize = 4 bytes (010)
when "10" => --Wrapping burst
-- The write address wraps when the address reaches wrap boundary
if (aw_wrap_en = '1') then
axi_awaddr <= std_logic_vector (unsigned(axi_awaddr) - (to_unsigned(aw_wrap_size,C_S_AXI_ADDR_WIDTH)));
else
axi_awaddr(C_S_AXI_ADDR_WIDTH - 1 downto ADDR_LSB) <= std_logic_vector (unsigned(axi_awaddr(C_S_AXI_ADDR_WIDTH - 1 downto ADDR_LSB)) + 1);--awaddr aligned to 4 byte boundary
axi_awaddr(ADDR_LSB-1 downto 0) <= (others => '0'); ----for awsize = 4 bytes (010)
end if;
when others => --reserved (incremental burst for example)
axi_awaddr(C_S_AXI_ADDR_WIDTH - 1 downto ADDR_LSB) <= std_logic_vector (unsigned(axi_awaddr(C_S_AXI_ADDR_WIDTH - 1 downto ADDR_LSB)) + 1);--for awsize = 4 bytes (010)
axi_awaddr(ADDR_LSB-1 downto 0) <= (others => '0');
end case;
end if;
end if;
end if;
end process;
process (S_AXI_ACLK)
begin
if rising_edge(S_AXI_ACLK) then
if S_AXI_ARESETN = '0' then
axi_wready <= '0';
else
if (axi_wready = '0' and S_AXI_WVALID = '1' and axi_awv_awr_flag = '1') then
axi_wready <= '1';
-- elsif (axi_awv_awr_flag = '0') then
elsif (S_AXI_WLAST = '1' and axi_wready = '1') then
axi_wready <= '0';
end if;
end if;
end if;
end process;
process (S_AXI_ACLK)
begin
if rising_edge(S_AXI_ACLK) then
if S_AXI_ARESETN = '0' then
axi_bvalid <= '0';
axi_bresp <= "00"; --need to work more on the responses
axi_buser <= (others => '0');
else
if (axi_awv_awr_flag = '1' and axi_wready = '1' and S_AXI_WVALID = '1' and axi_bvalid = '0' and S_AXI_WLAST = '1' ) then
axi_bvalid <= '1';
axi_bresp <= "00";
elsif (S_AXI_BREADY = '1' and axi_bvalid = '1') then
--check if bready is asserted while bvalid is high)
axi_bvalid <= '0';
end if;
end if;
end if;
end process;
process (S_AXI_ACLK)
begin
if rising_edge(S_AXI_ACLK) then
if S_AXI_ARESETN = '0' then
axi_arready <= '0';
axi_arv_arr_flag <= '0';
else
if (axi_arready = '0' and S_AXI_ARVALID = '1' and axi_awv_awr_flag = '0' and axi_arv_arr_flag = '0') then
axi_arready <= '1';
axi_arv_arr_flag <= '1';
elsif (axi_rvalid = '1' and S_AXI_RREADY = '1' and (axi_arlen_cntr = axi_arlen)) then
-- preparing to accept next address after current read completion
axi_arv_arr_flag <= '0';
else
axi_arready <= '0';
end if;
end if;
end if;
end process;
process (S_AXI_ACLK)
begin
if rising_edge(S_AXI_ACLK) then
if S_AXI_ARESETN = '0' then
axi_araddr <= (others => '0');
axi_arburst <= (others => '0');
axi_arlen <= (others => '0');
axi_arlen_cntr <= (others => '0');
axi_rlast <= '0';
axi_ruser <= (others => '0');
else
if (axi_arready = '0' and S_AXI_ARVALID = '1' and axi_arv_arr_flag = '0') then
-- address latching
axi_araddr <= S_AXI_ARADDR(C_S_AXI_ADDR_WIDTH - 1 downto 0); ---- start address of transfer
axi_arlen_cntr <= (others => '0');
axi_rlast <= '0';
axi_arburst <= S_AXI_ARBURST;
axi_arlen <= S_AXI_ARLEN;
elsif((axi_arlen_cntr <= axi_arlen) and axi_rvalid = '1' and S_AXI_RREADY = '1') then
axi_arlen_cntr <= std_logic_vector (unsigned(axi_arlen_cntr) + 1);
axi_rlast <= '0';
case (axi_arburst) is
when "00" => -- fixed burst
-- The read address for all the beats in the transaction are fixed
axi_araddr <= axi_araddr; ----for arsize = 4 bytes (010)
when "01" => --incremental burst
-- The read address for all the beats in the transaction are increments by awsize
axi_araddr(C_S_AXI_ADDR_WIDTH - 1 downto ADDR_LSB) <= std_logic_vector (unsigned(axi_araddr(C_S_AXI_ADDR_WIDTH - 1 downto ADDR_LSB)) + 1); --araddr aligned to 4 byte boundary
axi_araddr(ADDR_LSB-1 downto 0) <= (others => '0'); ----for awsize = 4 bytes (010)
when "10" => --Wrapping burst
-- The read address wraps when the address reaches wrap boundary
if (ar_wrap_en = '1') then
axi_araddr <= std_logic_vector (unsigned(axi_araddr) - (to_unsigned(ar_wrap_size,C_S_AXI_ADDR_WIDTH)));
else
axi_araddr(C_S_AXI_ADDR_WIDTH - 1 downto ADDR_LSB) <= std_logic_vector (unsigned(axi_araddr(C_S_AXI_ADDR_WIDTH - 1 downto ADDR_LSB)) + 1); --araddr aligned to 4 byte boundary
axi_araddr(ADDR_LSB-1 downto 0) <= (others => '0'); ----for awsize = 4 bytes (010)
end if;
when others => --reserved (incremental burst for example)
axi_araddr(C_S_AXI_ADDR_WIDTH - 1 downto ADDR_LSB) <= std_logic_vector (unsigned(axi_araddr(C_S_AXI_ADDR_WIDTH - 1 downto ADDR_LSB)) + 1);--for arsize = 4 bytes (010)
axi_araddr(ADDR_LSB-1 downto 0) <= (others => '0');
end case;
elsif((axi_arlen_cntr = axi_arlen) and axi_rlast = '0' and axi_arv_arr_flag = '1') then
axi_rlast <= '1';
elsif (S_AXI_RREADY = '1') then
axi_rlast <= '0';
end if;
end if;
end if;
end process;
process (S_AXI_ACLK)
begin
if rising_edge(S_AXI_ACLK) then
if S_AXI_ARESETN = '0' then
axi_rvalid <= '0';
axi_rresp <= "00";
else
if (axi_arv_arr_flag = '1' and axi_rvalid = '0') then
axi_rvalid <= '1';
axi_rresp <= "00"; -- 'OKAY' response
elsif (axi_rvalid = '1' and S_AXI_RREADY = '1') then
axi_rvalid <= '0';
end if;
end if;
end if;
end process;
---------------------------------------------------------------------------
-- 用户逻辑
---------------------------------------------------------------------------
ram_wren <= axi_wready and S_AXI_WVALID ;
ram_rden <= axi_arv_arr_flag ;
ram_address <= axi_araddr(ADDR_LSB+OPT_MEM_ADDR_BITS downto ADDR_LSB) when axi_arv_arr_flag = '1' else
axi_awaddr(ADDR_LSB+OPT_MEM_ADDR_BITS downto ADDR_LSB) when axi_awv_awr_flag = '1' else
(others => '0');
ram_data_in <= S_AXI_WDATA;
process (S_AXI_ACLK)
begin
if rising_edge(S_AXI_ACLK) then
if ram_wren = '1' then
RAM(to_integer(unsigned(ram_address))) <= ram_data_in;
end if;
ram_data_out <= RAM(to_integer(unsigned(ram_address)));
end if;
end process;
process(ram_data_out, axi_rvalid) is
begin
if (axi_rvalid = '1') then
axi_rdata <= ram_data_out;
else
axi_rdata <= (others => '0');
end if;
end process;
---------------------------------------------------------------------------
-- 观测信号
---------------------------------------------------------------------------
test( 0) <= S_AXI_ACLK;
test( 1) <= S_AXI_ARESETN;
test( 2) <= S_AXI_AWID(0);
test( 8 downto 3) <= S_AXI_AWADDR;
test( 9) <= '0';
test( 17 downto 10) <= S_AXI_AWLEN;
test( 20 downto 18) <= S_AXI_AWSIZE;
test( 22 downto 21) <= S_AXI_AWBURST;
test( 23) <= S_AXI_AWLOCK;
test( 27 downto 24) <= S_AXI_AWCACHE;
test( 30 downto 28) <= S_AXI_AWPROT;
test( 34 downto 31) <= S_AXI_AWQOS;
test( 38 downto 35) <= S_AXI_AWREGION;
test( 39) <= S_AXI_AWVALID;
test( 71 downto 40) <= S_AXI_WDATA;
test( 75 downto 72) <= S_AXI_WSTRB;
test( 76) <= S_AXI_WLAST;
test( 77) <= S_AXI_WVALID;
test( 78) <= S_AXI_BREADY;
test( 79) <= S_AXI_ARID(0);
test( 85 downto 80) <= S_AXI_ARADDR;
test( 86) <= '0';
test( 94 downto 87) <= S_AXI_ARLEN;
test( 97 downto 95) <= S_AXI_ARSIZE;
test( 99 downto 98) <= S_AXI_ARBURST;
test( 100) <= S_AXI_ARLOCK;
test(104 downto 101) <= S_AXI_ARCACHE;
test(107 downto 105) <= S_AXI_ARPROT;
test(111 downto 108) <= S_AXI_ARQOS;
test(115 downto 112) <= S_AXI_ARREGION;
test( 116) <= S_AXI_ARVALID;
test( 117) <= S_AXI_RREADY;
test( 118) <= axi_awready;
test( 119) <= axi_wready;
test( 120) <= axi_bresp(0);
test( 121) <= axi_bvalid;
test( 122) <= axi_arready;
test(154 downto 123) <= axi_rdata;
test(156 downto 155) <= axi_rresp;
test( 157) <= axi_rlast;
test( 158) <= axi_rvalid;
test( 159) <= S_AXI_AWID(0);
test( 160) <= S_AXI_ARID(0);
test(255 downto 161) <= (others=>'0');
end arch_imp;
注意memcpy的使用对读写时序的影响
C代码1
写时序
读时序
C代码2
写时序
读时序
C代码3
写时序
读时序
操控AXI BRAM
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity bram_op_wrapper is
port(
clk : in std_logic;
rst : in std_logic;
user_wr_en : in std_logic;
user_wr_len : in std_logic_vector( 7 downto 0); --突发传输数据个数-1
user_wr_addr : in std_logic_vector(11 downto 0);
user_wr_data : in std_logic_vector(31 downto 0);
user_rd_en : in std_logic;
user_rd_len : in std_logic_vector( 7 downto 0);
user_rd_addr : in std_logic_vector(11 downto 0);
user_rd_data : out std_logic_vector(31 downto 0);
user_rd_vld : out std_logic
);
end bram_op_wrapper;
architecture Behavioral of bram_op_wrapper is
--------------------------------------------------------------------------------
-- 类型定义
--------------------------------------------------------------------------------
type aw_state_type is (AW_ST0,AW_ST1,AW_ST2,AW_ST3);
type w_state_type is (W_ST0,W_ST1,W_ST2);
type ar_state_type is (AR_ST0,AR_ST1,AR_ST2,AR_ST3);
type r_state_type is (R_ST0,R_ST1,R_ST2);
--------------------------------------------------------------------------------
-- component声明
--------------------------------------------------------------------------------
component AXI_BRAM
port (
rsta_busy : out std_logic;
rstb_busy : out std_logic;
s_aclk : in std_logic;
s_aresetn : in std_logic;
s_axi_awid : in std_logic_vector(3 downto 0);
s_axi_awaddr : in std_logic_vector(31 downto 0);
s_axi_awlen : in std_logic_vector(7 downto 0);
s_axi_awsize : in std_logic_vector(2 downto 0);
s_axi_awburst : in std_logic_vector(1 downto 0);
s_axi_awvalid : in std_logic;
s_axi_awready : out std_logic;
s_axi_wdata : in std_logic_vector(31 downto 0);
s_axi_wstrb : in std_logic_vector(3 downto 0);
s_axi_wlast : in std_logic;
s_axi_wvalid : in std_logic;
s_axi_wready : out std_logic;
s_axi_bid : out std_logic_vector(3 downto 0);
s_axi_bresp : out std_logic_vector(1 downto 0);
s_axi_bvalid : out std_logic;
s_axi_bready : in std_logic;
s_axi_arid : in std_logic_vector(3 downto 0);
s_axi_araddr : in std_logic_vector(31 downto 0);
s_axi_arlen : in std_logic_vector(7 downto 0);
s_axi_arsize : in std_logic_vector(2 downto 0);
s_axi_arburst : in std_logic_vector(1 downto 0);
s_axi_arvalid : in std_logic;
s_axi_arready : out std_logic;
s_axi_rid : out std_logic_vector(3 downto 0);
s_axi_rdata : out std_logic_vector(31 downto 0);
s_axi_rresp : out std_logic_vector(1 downto 0);
s_axi_rlast : out std_logic;
s_axi_rvalid : out std_logic;
s_axi_rready : in std_logic
);
end component;
component FWFT_FIFO_W44_D512
port (
clk : in std_logic;
srst : in std_logic;
din : in std_logic_vector(43 downto 0);
wr_en : in std_logic;
rd_en : in std_logic;
dout : out std_logic_vector(43 downto 0);
full : out std_logic;
empty : out std_logic
);
end component;
--------------------------------------------------------------------------------
-- 信号声明
--------------------------------------------------------------------------------
-- axi bram相关信号
signal s_aresetn : std_logic;
signal s_axi_awid : std_logic_vector(3 downto 0);
signal s_axi_awaddr : std_logic_vector(31 downto 0);
signal s_axi_awlen : std_logic_vector(7 downto 0);
signal s_axi_awsize : std_logic_vector(2 downto 0);
signal s_axi_awburst : std_logic_vector(1 downto 0);
signal s_axi_awvalid : std_logic;
signal s_axi_awready : std_logic;
signal s_axi_wdata : std_logic_vector(31 downto 0);
signal s_axi_wstrb : std_logic_vector(3 downto 0);
signal s_axi_wlast : std_logic;
signal s_axi_wvalid : std_logic;
signal s_axi_wready : std_logic;
signal s_axi_bid : std_logic_vector(3 downto 0);
signal s_axi_bresp : std_logic_vector(1 downto 0);
signal s_axi_bvalid : std_logic;
signal s_axi_bready : std_logic;
signal s_axi_arid : std_logic_vector(3 downto 0);
signal s_axi_araddr : std_logic_vector(31 downto 0);
signal s_axi_arlen : std_logic_vector(7 downto 0);
signal s_axi_arsize : std_logic_vector(2 downto 0);
signal s_axi_arburst : std_logic_vector(1 downto 0);
signal s_axi_arvalid : std_logic;
signal s_axi_arready : std_logic;
signal s_axi_rid : std_logic_vector(3 downto 0);
signal s_axi_rdata : std_logic_vector(31 downto 0);
signal s_axi_rresp : std_logic_vector(1 downto 0);
signal s_axi_rlast : std_logic;
signal s_axi_rvalid : std_logic;
signal s_axi_rready : std_logic;
-- 写缓冲FIFO信号
signal wr_fifo_din : std_logic_vector(43 downto 0);
signal wr_fifo_wr_en : std_logic;
signal wr_fifo_rd_en : std_logic;
signal wr_fifo_dout : std_logic_vector(43 downto 0);
signal wr_fifo_full : std_logic;
signal wr_fifo_empty : std_logic;
-- 读缓冲FIFO信号
signal rd_fifo_din : std_logic_vector(43 downto 0);
signal rd_fifo_wr_en : std_logic;
signal rd_fifo_rd_en : std_logic;
signal rd_fifo_dout : std_logic_vector(43 downto 0);
signal rd_fifo_full : std_logic;
signal rd_fifo_empty : std_logic;
-- 复位信号
signal rst_L1 : std_logic := '0';
signal rst_cnt : unsigned(7 downto 0) := (others=>'0');
-- axi状态
signal aw_state : aw_state_type := AW_ST0;
signal w_state : w_state_type := W_ST0;
signal ar_state : ar_state_type := AR_ST0;
signal r_state : r_state_type := R_ST0;
signal wr_cnt : unsigned(7 downto 0) := (others=>'0');
begin
-----------------------------------------------------------------
-- axi复位
process(clk)
begin
if rising_edge(clk) then
rst_L1 <= rst;
if (rst_L1='0') and (rst='1') then
rst_cnt <= (others=>'0');
elsif (rst_cnt<20) then
rst_cnt <= rst_cnt + 1;
else
rst_cnt <= rst_cnt;
end if;
if (rst_cnt<20) then
s_aresetn <= '0';
else
s_aresetn <= '1';
end if;
end if;
end process;
-----------------------------------------------------------------
-- 状态机
process(clk)
begin
if rising_edge(clk) then
case aw_state is
when AW_ST0 =>
if (wr_fifo_empty='0') then -- FIFO中有数据,跳转状态
aw_state <= AW_ST1;
else
aw_state <= AW_ST0;
end if;
when AW_ST1 =>
if (s_axi_awready='1') then
aw_state <= AW_ST2;
else
aw_state <= AW_ST1;
end if;
when AW_ST2 =>
if (wr_cnt=unsigned(user_wr_len)) then
aw_state <= AW_ST3;
else
aw_state <= AW_ST2;
end if;
when AW_ST3 =>
aw_state <= AW_ST0;
when others =>
aw_state <= AW_ST0;
end case;
case w_state is
when W_ST0 =>
wr_cnt <= (others=>'0');
if (wr_fifo_empty='0') then -- FIFO中有数据,跳转状态
w_state <= W_ST1;
else
w_state <= W_ST0;
end if;
when W_ST1 =>
if (s_axi_wready='1') then
wr_cnt <= wr_cnt + 1;
else
wr_cnt <= wr_cnt;
end if;
if (wr_cnt=unsigned(user_wr_len)) then
w_state <= W_ST2;
else
w_state <= W_ST1;
end if;
when W_ST2 =>
wr_cnt <= (others=>'0');
w_state <= W_ST0;
when others =>
w_state <= W_ST0;
end case;
end if;
end process;
-- 写地址通道
s_axi_awid <= "0000";
s_axi_awsize <= "010";
s_axi_awburst <= "01";
s_axi_awlen <= user_wr_len;
s_axi_awaddr <= std_logic_vector(to_unsigned(0,18)) & wr_fifo_dout(43 downto 32) & "00"; -- 设置突发写地址
process(aw_state)
begin
case aw_state is
when AW_ST0 =>
s_axi_awvalid <= '0';
when AW_ST1 =>
s_axi_awvalid <= '1';
when AW_ST2 =>
s_axi_awvalid <= '0';
when others =>
s_axi_awvalid <= '0';
end case;
end process;
-- 写数据通道
s_axi_wstrb <= "1111";
s_axi_wdata <= wr_fifo_dout(31 downto 0);
process(s_axi_wready,wr_fifo_empty,w_state,wr_cnt)
begin
case w_state is
when W_ST0 =>
wr_fifo_rd_en <= '0';
s_axi_wlast <= '0';
s_axi_wvalid <= '0';
when W_ST1 =>
wr_fifo_rd_en <= s_axi_wready and (not wr_fifo_empty);
if (wr_cnt=unsigned(user_wr_len)) then
s_axi_wlast <= '1';
else
s_axi_wlast <= '0';
end if;
s_axi_wvalid <= '1';
when W_ST2 =>
wr_fifo_rd_en <= '0';
s_axi_wlast <= '0';
s_axi_wvalid <= '0';
when others =>
wr_fifo_rd_en <= '0';
s_axi_wlast <= '0';
s_axi_wvalid <= '0';
end case;
end process;
-- 写响应通道
process(s_axi_bresp,s_axi_bvalid)
begin
if (s_axi_bresp="00") and (s_axi_bvalid='1') then
s_axi_bready <= '1';
else
s_axi_bready <= '0';
end if;
end process;
-----------------------------------------------------------------
-- 状态机
process(clk)
begin
if rising_edge(clk) then
case ar_state is
when AR_ST0 =>
if (rd_fifo_empty='0') then -- FIFO中有数据,跳转状态
ar_state <= AR_ST1;
else
ar_state <= AR_ST0;
end if;
when AR_ST1 =>
if (s_axi_arready='1') then
ar_state <= AR_ST2;
else
ar_state <= AR_ST1;
end if;
when AR_ST2 =>
if (s_axi_rlast='1') then
ar_state <= AR_ST3;
else
ar_state <= AR_ST2;
end if;
when AR_ST3 =>
ar_state <= AR_ST0;
when others =>
ar_state <= AR_ST0;
end case;
case r_state is
when R_ST0 =>
if (rd_fifo_empty='0') then -- FIFO中有数据,跳转状态
r_state <= R_ST1;
else
r_state <= R_ST0;
end if;
when R_ST1 =>
if (s_axi_rlast='1') then
r_state <= R_ST2;
else
r_state <= R_ST1;
end if;
when R_ST2 =>
r_state <= R_ST0;
when others =>
r_state <= R_ST0;
end case;
end if;
end process;
-- 读地址通道
s_axi_arid <= (others=>'0');
s_axi_arsize <= "010";
s_axi_arburst <= "01";
s_axi_arlen <= user_rd_len;
s_axi_araddr <= std_logic_vector(to_unsigned(0,18)) & rd_fifo_dout(43 downto 32) & "00"; -- 设置突发读地址
process(ar_state)
begin
case ar_state is
when AR_ST0 =>
s_axi_arvalid <= '0';
when AR_ST1 =>
s_axi_arvalid <= '1';
when AR_ST2 =>
s_axi_arvalid <= '0';
when AR_ST3 =>
s_axi_arvalid <= '0';
when others =>
s_axi_arvalid <= '0';
end case;
end process;
-- 读数据通道
process(r_state,s_axi_rlast,s_axi_rvalid,s_axi_rdata)
begin
case r_state is
when R_ST0 =>
s_axi_rready <= '0';
rd_fifo_rd_en <= '0';
user_rd_vld <= '0';
user_rd_data <= (others=>'0');
when R_ST1 =>
if (s_axi_rlast='1') then
rd_fifo_rd_en <= '1';
else
rd_fifo_rd_en <= '0';
end if;
s_axi_rready <= '1';
user_rd_vld <= s_axi_rvalid;
user_rd_data <= s_axi_rdata;
when R_ST2 =>
s_axi_rready <= '0';
rd_fifo_rd_en <= '0';
when others =>
s_axi_rready <= '0';
rd_fifo_rd_en <= '0';
user_rd_vld <= '0';
user_rd_data <= (others=>'0');
end case;
end process;
-----------------------------------------------------------------
-- 例化axi bram
Inst_AXI_BRAM : AXI_BRAM
port map(
rsta_busy => open,
rstb_busy => open,
s_aclk => clk,
s_aresetn => s_aresetn,
s_axi_awid => s_axi_awid,
s_axi_awaddr => s_axi_awaddr,
s_axi_awlen => s_axi_awlen,
s_axi_awsize => s_axi_awsize,
s_axi_awburst => s_axi_awburst,
s_axi_awvalid => s_axi_awvalid,
s_axi_awready => s_axi_awready,
s_axi_wdata => s_axi_wdata,
s_axi_wstrb => s_axi_wstrb,
s_axi_wlast => s_axi_wlast,
s_axi_wvalid => s_axi_wvalid,
s_axi_wready => s_axi_wready,
s_axi_bid => s_axi_bid,
s_axi_bresp => s_axi_bresp,
s_axi_bvalid => s_axi_bvalid,
s_axi_bready => s_axi_bready,
s_axi_arid => s_axi_arid,
s_axi_araddr => s_axi_araddr,
s_axi_arlen => s_axi_arlen,
s_axi_arsize => s_axi_arsize,
s_axi_arburst => s_axi_arburst,
s_axi_arvalid => s_axi_arvalid,
s_axi_arready => s_axi_arready,
s_axi_rid => s_axi_rid,
s_axi_rdata => s_axi_rdata,
s_axi_rresp => s_axi_rresp,
s_axi_rlast => s_axi_rlast,
s_axi_rvalid => s_axi_rvalid,
s_axi_rready => s_axi_rready
);
-----------------------------------------------------------------
-- 例化FIFO
wr_fifo_wr_en <= user_wr_en;
wr_fifo_din <= user_wr_addr & user_wr_data;
Inst_WR_FWFT_FIFO_W44_D512 : FWFT_FIFO_W44_D512
port map(
clk => clk,
srst => rst,
din => wr_fifo_din,
wr_en => wr_fifo_wr_en,
rd_en => wr_fifo_rd_en,
dout => wr_fifo_dout,
full => wr_fifo_full,
empty => wr_fifo_empty
);
rd_fifo_wr_en <= user_rd_en;
rd_fifo_din <= user_rd_addr & X"00000000";
Inst_RD_FWFT_FIFO_W44_D512 : FWFT_FIFO_W44_D512
port map(
clk => clk,
srst => rst,
din => rd_fifo_din,
wr_en => rd_fifo_wr_en,
rd_en => rd_fifo_rd_en,
dout => rd_fifo_dout,
full => rd_fifo_full,
empty => rd_fifo_empty
);
end Behavioral;
博文链接
ZYNQ+Vivado2015.2系列(七)软硬件联合Debug观察AXI总线读、写时各信号的时序
AXI4 & AXI4-stream 相关笔记
AXI协议中的模棱两可的含义的解释
【JokerのZYNQ7020】AXI4_FULL。