01AXI4总线axi-lite-slave(AXI4总线实战)


软件版本:vitis2020.2(vivado2020.2)

操作系统:WIN10 64bit

硬件平台:适用XILINX A7/K7/Z7/ZU/KU系列FPGA(米联客MZU07A-EG开发硬件平台)

登录"米联客"FPGA社区-www.uisrc.com视频课程、答疑解惑!

1.1概述

    使用XILINX 的软件工具VIVADO以及XILINX的7代以上的FPGA或者SOC掌握AXI-4总线结束,并且可以灵活使用AXI-4总线技术完成数据的交换,可以让我们在构建强大的FPGA内部总线数据互联通信方面取得高效、高速、标准化的优势。

本文实验目的:

1:学习AXI总线协议包括AXI-FULL、AXI-Lite

2:掌握基于VIVADO工具产生AXI协议模板

3:掌握通过VIVADO工具产生AXI-lite-Slave代码,并且会修改寄存器

4:理解AXI-lite-Slave中自定义寄存器的地址分配

5:掌握通过VIVADO封装AXI-LITE-SLAVE 图形化IP

6:通过仿真验证AXI-LITE IP的工作是否正常。

1.2AXI总线协议介绍

1.2.1AXI总线概述

在XIINX FPGA的软件工具vivado以及相关IP中有支持三种AXI总线,拥有三种AXI接口,当然用的都是AXI协议。其中三种AXI总线分别为:

AXI4:(For high-performance memory-mapped requirements.)主要面向高性能地址映射通信的需求,是面向地址映射的接口,允许最大256轮的数据突发传输;

AXI4-Lite:(For simple, low-throughput memory-mapped communication )是一个轻量级的地址映射单次传输接口,占用很少的逻辑单元。

AXI4-Stream:(For high-speed streaming data.)面向高速流数据传输;去掉了地址项,允许无限制的数据突发传输规模。

由于AXI4和AXI4-Lite信号大部分一样,以下只介绍AXI4信号.另外对于AXI4-Stream协议不再本文中接收,后面有单独介绍的文章。

1.2.2AXI-4总线信号功能

1:时钟和复位

信号

方向

描述

ACLK  

时钟源  

全局时钟信号

ARESETn  

复位源

全局复位信号,低有效

 

写地址通道信号:

信号

方向

描述

AWID 

主机to从机

写地址ID,用来标志一组写信号

AWADDR 

主机to从机

写地址,给出一次写突发传输的写地址

AWLEN 

主机to从机

AWLEN[7:0]决定写传输的突发长度。AXI3只支持1~16次的突发传输(Burst_length=AxLEN[3:0]+1),AXI4扩展突发长度支持INCR突发类型为1~256次传输,对于其他的传输类型依然保持1~16次突发传输(Burst_Length=AxLEN[7:0]+1)。

burst传输具有如下规则:

wraping burst ,burst长度必须是2,4,8,16

burst不能跨4KB边界

不支持提前终止burst传输

AWSIZE 

主机to从机

写突发大小,给出每次突发传输的字节数支持1248163264128

AWBURST 

主机to从机

突发类型:

2'b00 FIXED:突发传输过程中地址固定,用于FIFO访问

2'b01 INCR :增量突发,传输过程中,地址递增。增加量取决AxSIZE的值。

2'b10 WRAP:回环突发,和增量突发类似,但会在特定高地址的边界处回到低地址处。回环突发的长度只能是2,4,8,16次传输,传输首地址和每次传输的大小对齐。最低的地址整个传输的数据大小对齐。回环边界等于(AxSIZE*AxLEN

2'b11 Reserved 

AWLOCK 

主机to从机

总线锁信号,可提供操作的原子性

AWCACHE 

主机to从机

内存类型,表明一次传输是怎样通过系统的

AWPROT 

主机to从机

保护类型,表明一次传输的特权级及安全等级

AWQOS 

主机to从机

质量服务QoS

AWREGION 

主机to从机

区域标志,能实现单一物理接口对应的多个逻辑接口

AWUSER 

主机to从机

用户自定义信号

AWVALID 

主机to从机

有效信号,表明此通道的地址控制信号有效

AWREADY 

从机to主机

表明""可以接收地址和对应的控制信号

 

2:写数据通道信号:

信号名    

方向    

描述      

WID 

主机to从机

一次写传输的ID tag

WDATA 

主机to从机

写数据

WSTRB 

主机to从机

WSTRB[n:0]对应于对应的写字节,WSTRB[n]对应WDATA[8n+7:8n]WVALID为低时,WSTRB可以为任意值,WVALID为高时,WSTRB为高的字节线必须指示有效的数据。

WLAST 

主机to从机

表明此次传输是最后一个突发传输

WUSER 

主机to从机

用户自定义信号

WVALID 

主机to从机

写有效,表明此次写有效

WREADY 

从机to主机

表明从机可以接收写数据

 

写响应信号:

信号名    

方向    

描述      

BID 

从机to主机

写响应ID tag

BRESP 

从机to主机

写响应,表明写传输的状态

BUSER 

从机to主机

用户自定义

BVALID 

从机to主机

写响应有效

BREADY 

主机to从机

表明主机能够接收写响应

3:读地址通道信号:

信号

方向

描述

ARID

主机to从机

读地址ID,用来标志一组写信号

ARADDR

主机to从机

读地址,给出一次读突发传输的读地址

ARLEN

主机to从机

ARLEN[7:0]决定读传输的突发长度。AXI3只支持1~16次的突发传输(Burst_length=AxLEN[3:0]+1),AXI4扩展突发长度支持INCR突发类型为1~256次传输,对于其他的传输类型依然保持1~16次突发传输(Burst_Length=AxLEN[7:0]+1)。

burst传输具有如下规则:

wraping burst ,burst长度必须是2,4,8,16

burst不能跨4KB边界

不支持提前终止burst传输

ARSIZE

主机to从机

读突发大小,给出每次突发传输的字节数支持1248163264128

ARBURST

主机to从机

突发类型:

2'b00 FIXED:突发传输过程中地址固定,用于FIFO访问

2'b01 INCR :增量突发,传输过程中,地址递增。增加量取决AxSIZE的值。

2'b10 WRAP:回环突发,和增量突发类似,但会在特定高地址的边界处回到低地址处。回环突发的长度只能是2,4,8,16次传输,传输首地址和每次传输的大小对齐。最低的地址整个传输的数据大小对齐。回环边界等于(AxSIZE*AxLEN

2'b11 Reserved 

ARLOCK

主机to从机

总线锁信号,可提供操作的原子性

ARCACHE

主机to从机

内存类型,表明一次传输是怎样通过系统的

ARPROT

主机to从机

保护类型,表明一次传输的特权级及安全等级

ARQOS

主机to从机

质量服务QoS

ARREGION

主机to从机

区域标志,能实现单一物理接口对应的多个逻辑接口

ARUSER

主机to从机

用户自定义信号

ARVALID

主机to从机

有效信号,表明此通道的地址控制信号有效

ARREADY

从机to主机

表明""可以接收地址和对应的控制信号

4:读数据通道信号:

信号名    

方向    

描述      

RID

从机to主机

一次读传输的ID tag

RDATA

从机to主机

读数据

RRESP 

从机to主机

读响应,表明读传输的状态

RLAST

从机to主机

表明此次传输是最后一个突发传输

RUSER

从机to主机

用户自定义信号

RVALID

从机to主机

写有效,表明此次写有效

RREADY

主机to从机

表明从机可以接收写数据

1.2.3数据有效的情况

AXI4所采用的是一种READY,VALID握手通信机制,简单来说主从双方进行数据通信前,有一个握手的过程。传输源产生VLAID信号来指明何时数据或控制信息有效。而目地源产生READY信号来指明已经准备好接受数据或控制信息。传输发生在VALID和READY信号同时为高的时候。VALID和READY信号的出现有三种关系。

  1. VALID先变高READY后变高。时序图如下:

    在箭头处信息传输发生。

  2. READY先变高VALID后变高。时序图如下:

    同样在箭头处信息传输发生。

  3. VALID和READY信号同时变高。时序图如下:

    在这种情况下,信息传输立马发生,如图箭头处指明信息传输发生。

    1.2.4突发式读写

    1:突发式写时序图

    这一过程的开始时,主机发送地址和控制信息到写地址通道中,然后主机发送每一个写数据到写数据通道中。当主机发送最后一个数据时,WLAST信号就变为高。当设备接收完所有数据之后他将一个写响应发送回主机来表明写事务完成。

    2:突发式读的时序图

    当地址出现在地址总线后,传输的数据将出现在读数据通道上。设备保持VALID为低直到读数据有效。为了表明一次突发式读写的完成,设备用RLAST信号来表示最后一个被传输的数据。

    1.3创建axi4-lite-slave总线接口IP

    新建fpga工程,过程省略

    新建完成工程后,单击菜单栏Tools->Create and Package New IP,开始创建一个AXI4-Lite接口总线IP

    选择使用vivado自带的AXI总线模板创建一个AXI4-Lite接口IP

    设置IP的名字为saxi_lite

     

    模板支持3中协议,分别是AXI4-Full AXI4-Lite AXI4-Stream

    总线包括Master和Slave两种模式,这里选择Slave模式

    这里选择Verify Peripheral IP using AXI4 VIP 可以对AXI4-Lite快速验证

    单击Finish 后展开VIVADO自动产生的demo,单击Block Design的工程,可以看到如下2个IP。其中saxi_lite_0就是我们自定义的IP,另外一个master_0是用来读写我们自定义的saxi_lite_0,以此验证我们的IP正确性。

    继续站看代码看看里面有什么东西

    右击Generate Output Products

    路径uisrc/03_ip/saxi_lite_1.0/hdl路径下的saxi_lite_v_0_S00_AXI.v就是我们的源码。另外一个saxi_lite_v1_0.v是软件产生了一个接口文件,如果我们自己定义IP可有可无。

    1.4程序分析

    axi总线信号的关键无非是地址和数据,而写地址的有效取决于AXI_AWVALID和AXI_AWREADY,写数据的有效取决于S_AXI_WVALID和S_AXI_WREADY。同理,读地址的有效取决于AXI_ARVALID和AXI_ARREADY,读数据的有效取决于S_AXI_RVALID和S_AXI_RREADY。所以以下代码的阅读分析注意也是围绕以上4个信号的有效时序。

    以下程序我们把关键信号的代码拆分阅读

    1:axi-lite-slave的axi_awready

        always @( posedge S_AXI_ACLK )

        begin

         if ( S_AXI_ARESETN == 1'b0 )

         begin

         axi_awready <= 1'b0;

         aw_en <= 1'b1;

         end

         else

         begin

         if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID && aw_en)

         begin

         // 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'b1;

         aw_en <= 1'b0;

         end

         else if (S_AXI_BREADY && axi_bvalid)

         begin

         aw_en <= 1'b1;

         axi_awready <= 1'b0;

         end

         else

         begin

         axi_awready <= 1'b0;

         end

         end

        end  

    2:axi-lite-slave的axi_awaddr

        always @( posedge S_AXI_ACLK )

        begin

         if ( S_AXI_ARESETN == 1'b0 )

         begin

         axi_awaddr <= 0;

         end

         else

         begin

         if (~axi_awready && S_AXI_AWVALID && S_AXI_WVALID && aw_en)

         begin

         // Write Address latching

         axi_awaddr <= S_AXI_AWADDR;

         end

         end

        end  

    3:axi-lite-slave的axi_wready

    当满足(~axi_wready && S_AXI_WVALID && S_AXI_AWVALID && aw_en )==1条件,设置axi_wready有效。

        always @( posedge S_AXI_ACLK )

        begin

         if ( S_AXI_ARESETN == 1'b0 )

         begin

         axi_wready <= 1'b0;

         end

         else

         begin

         if (~axi_wready && S_AXI_WVALID && S_AXI_AWVALID && aw_en )

         begin

         // 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'b1;

         end

         else

         begin

         axi_wready <= 1'b0;

         end

         end

        end  

    4:axi-lite-slave的写数据寄存器

    axi-lite-slave很重要一点功能就是配合SOC的处理器部分完成一些低速外设,或者寄存器的控制。需要使用多寄存器或者外设,一般在ip代码里面就已经设置好了。前面用vivado的模板产生自定义ip的时候,我们选择了4个32bits寄存器,以下的模板中slv_reg0~ slv_reg3共计4个32bits寄存器。

        assign slv_reg_wren = axi_wready && S_AXI_WVALID && axi_awready && S_AXI_AWVALID;

     

        always @( posedge S_AXI_ACLK )

        begin

         if ( S_AXI_ARESETN == 1'b0 )

         begin

         slv_reg0 <= 0;

         slv_reg1 <= 0;

         slv_reg2 <= 0;

         slv_reg3 <= 0;

         end

         else begin

         if (slv_reg_wren)

         begin

         case ( axi_awaddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )

         2'h0:

         for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

         if ( S_AXI_WSTRB[byte_index] == 1 ) begin

         // Respective byte enables are asserted as per write strobes

         // Slave register 0

         slv_reg0[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];

         end

         2'h1:

         for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

         if ( S_AXI_WSTRB[byte_index] == 1 ) begin

         // Respective byte enables are asserted as per write strobes

         // Slave register 1

         slv_reg1[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];

         end

         2'h2:

         for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

         if ( S_AXI_WSTRB[byte_index] == 1 ) begin

         // Respective byte enables are asserted as per write strobes

         // Slave register 2

         slv_reg2[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];

         end

         2'h3:

         for ( byte_index = 0; byte_index <= (C_S_AXI_DATA_WIDTH/8)-1; byte_index = byte_index+1 )

         if ( S_AXI_WSTRB[byte_index] == 1 ) begin

         // Respective byte enables are asserted as per write strobes

         // Slave register 3

         slv_reg3[(byte_index*8) +: 8] <= S_AXI_WDATA[(byte_index*8) +: 8];

         end

         default : begin

         slv_reg0 <= slv_reg0;

         slv_reg1 <= slv_reg1;

         slv_reg2 <= slv_reg2;

         slv_reg3 <= slv_reg3;

         end

         endcase

         end

         end

        end

    5:axi-lite-slave的axi_bvalid信号

    axi_bvalid用于告知axi master axi-slave端已经完成数据接收了

        always @( posedge S_AXI_ACLK )

        begin

         if ( S_AXI_ARESETN == 1'b0 )

         begin

         axi_bvalid <= 0;

         axi_bresp <= 2'b0;

         end

         else

         begin

         if (axi_awready && S_AXI_AWVALID && ~axi_bvalid && axi_wready && S_AXI_WVALID)

         begin

         // indicates a valid write response is available

         axi_bvalid <= 1'b1;

         axi_bresp <= 2'b0; // 'OKAY' response

         end // work error responses in future

         else

         begin

         if (S_AXI_BREADY && axi_bvalid)

         //check if bready is asserted while bvalid is high)

         //(there is a possibility that bready is always asserted high)

         begin

         axi_bvalid <= 1'b0;

         end

         end

         end

        end

    6:axi-lite-slave的axi_arready

    当条件满足(~axi_arready && S_AXI_ARVALID)==1设置axi_arready有效,并且寄存住总线上的地址axi_araddr <= S_AXI_ARADDR

        always @( posedge S_AXI_ACLK )

        begin

         if ( S_AXI_ARESETN == 1'b0 )

         begin

         axi_arready <= 1'b0;

         axi_araddr <= 32'b0;

         end

         else

         begin

         if (~axi_arready && S_AXI_ARVALID)

         begin

         // indicates that the slave has acceped the valid read address

         axi_arready <= 1'b1;

         // Read address latching

         axi_araddr <= S_AXI_ARADDR;

         end

         else

         begin

         axi_arready <= 1'b0;

         end

         end

        end

    7:axi-lite-slave的axi_araddr

        always @( posedge S_AXI_ACLK )

        begin

         if ( S_AXI_ARESETN == 1'b0 )

         begin

         axi_arready <= 1'b0;

         axi_araddr <= 32'b0;

         end

         else

         begin

         if (~axi_arready && S_AXI_ARVALID)

         begin

         // indicates that the slave has acceped the valid read address

         axi_arready <= 1'b1;

         // Read address latching

         axi_araddr <= S_AXI_ARADDR;

         end

         else

         begin

         axi_arready <= 1'b0;

         end

         end

        end

    8:axi-lite-slave的axi_rvalid信号

    当条件满足(axi_arready && S_AXI_ARVALID && ~axi_rvalid)==1的时候设置axi_rvalid有效,表示axi-lite-slave总线上的数据是有效的。

        always @( posedge S_AXI_ACLK )

        begin

         if ( S_AXI_ARESETN == 1'b0 )

         begin

         axi_rvalid <= 0;

         axi_rresp <= 0;

         end

         else

         begin

         if (axi_arready && S_AXI_ARVALID && ~axi_rvalid)

         begin

         // Valid read data is available at the read data bus

         axi_rvalid <= 1'b1;

         axi_rresp <= 2'b0; // 'OKAY' response

         end

         else if (axi_rvalid && S_AXI_RREADY)

         begin

         // Read data is accepted by the master

         axi_rvalid <= 1'b0;

         end

         end

        end

     

    assign S_AXI_RVALID    = axi_rvalid;

     

    9:axi-lite-slave的读数据寄存器

    本文实验中,axi-master写入4个寄存器数据,然后读出,通过查看数据是否一致可以确认axi-lite-slave工作是否正常。当slv_reg_rden有效的时候,数据被读入寄存器axi_rdata,当axi_rvalid有效的时候,数据被锁存。

    assign slv_reg_rden = axi_arready & S_AXI_ARVALID & ~axi_rvalid;

        

    always @(*)

        begin

         // Address decoding for reading registers

         case ( axi_araddr[ADDR_LSB+OPT_MEM_ADDR_BITS:ADDR_LSB] )

         2'h0 : reg_data_out <= slv_reg0;

         2'h1 : reg_data_out <= slv_reg1;

         2'h2 : reg_data_out <= slv_reg2;

         2'h3 : reg_data_out <= slv_reg3;

         default : reg_data_out <= 0;

         endcase

        end

     

        always @( posedge S_AXI_ACLK )

        begin

         if ( S_AXI_ARESETN == 1'b0 )

         begin

         axi_rdata <= 0;

         end

         else

         begin

         // When there is a valid read address (S_AXI_ARVALID) with

         // acceptance of read address by the slave (axi_arready),

         // output the read dada

         if (slv_reg_rden)

         begin

         axi_rdata <= reg_data_out; // register read data

         end

         end

        end

     

    当我们阅读后分析完以上代码后,可以发现,axi-lite-slave的代码中没有突发长度的处理,每次只处理一个地址的一个数据。并且也没有WLAST和RLAST信号,说明axi-lite-slave适合一些低速的数据交互,但是可以节省一些FPGA的逻辑资源。

    1.5实验结果

    单击仿真

     

     

    添加观察信号

    AXI总下依次写入1 2 3 4,slv_reg0~slv_reg3完成数据寄存

    读数据

     


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM