AXI协议与自定义AXI4-Lite外设

引言

  之前在Xilinx的FPGA上做设计,只是知道AXI接口,但是没有详细地了解过这个协议,现在需要用AXI总线做整个系统的设计了,所以还是有必要详细了解一下这个协议。

参考资料

IHI0022H: AMBA AXI and ACE Protocol Specification
IHI0051A: AMBA 4 AXI4-Stream Protocol Specification
  上面这两篇都是ARM官方的文档,都可以在ARM的官网找到,这两个文档对AXI4、AXI4-Lite和AXI4-Stream做了详细的介绍。除了这两个文档,再就是Xilinx的几个IP的文档了,有AXI Interconnect、SmartConnect、AXI4-Stream Interconnect,这三个只需要大致看一下就行。
  网上也有很多介绍AXI协议的帖子,也都写得非常好,而且也比较详细。本文的内容会比较少,因为都只是我在阅读过程中做的一些笔记,如果真心想了解这些内容,强烈建议要用心阅读上面两篇Specification!

AXI 协议

  • 特点
    • 地址、控制和数据分开控制
    • 支持非对齐的数据传输
    • 支持突发传输
    • 读写通道分开
    • 支持乱序传输
  • AXI 结构
    • 有AR、R、AW、W、B 五个独立通道,分别对应读地址、读数据、写地址、写数据、写响应。
    • 地址通道带有控制信息
    • B是响应通道,用来返回写响应
    • R通道不仅有读的数据也有响应信息
    • 总线互连的时候,公用地址和数据总线;或者公用地址线,多条数据总线;再或者有多条地址和数据总线。
  • 全局信号
    • 时钟,上升沿采样;复位低电平有效
  • 时钟与复位
    • 时钟 上升沿有效,接口之间的信号没有组合逻辑通路
    • 复位可以是异步复位但一定要同步释放
    • 复位的时候 manager端的AW、AR、W通道的VALID信号都要是low;subordinate端的R、B通道的VALID信号都要是low
    • VALID只有在复位撤销后的第一个时钟上升沿才能变为有效
    • 同一通道的VALID信号不能依赖READY信号
    • VALID有效之后只有出现READY才能撤销
    • destination可以等待VALID出现再产生READY
    • READY出现之后,可以在VALID出现之前撤销
  • 通道信号
    • 建议AWREADY和ARREADY默认为高电平,这样可以比较快
    • 推荐inactive的byte lanes的WDATA RDATA是低电平
  • 通道之间的关系
    • 写响应要在写数据的LAST信号有效之后产生
    • 读数据要在读地址送给subordinate之后送出数据
    • 协议里面之规定了这两组关系,也就是说可能会有比如写数据比写地址先到或者后到的情况,这些都是允许的。
  • 事务结构
    • AXI协议是基于突发(burst)传输的,突发传输由subordinate计算地址,因为manager只会发一个起始地址,后面字节的地址得靠subordinate来计算。
    • 不能超过4kB地址边界
    • AxBurst定义了突发的类型,突发不能终止
    • 有三类突发,INCR,FIXED,WRAP。INCR是地址自增的,FIXED是地址固定的,WRAP是会地址回滚的,它跟INCR类似,但就是传输过程中如果地址到了上边界,它就会让地址再回到下边界。
    • AxLEN表示突发的长度,就是一次burst有几次VALID和READY的握手;AxSize表示一次传输的字节个数,就是一次VALID和READY的握手传输多少个字节。
    • WRAP的突发长度不能超过16,INCR虽然可以超过,但实际上是转换成多个16长度的突发
    • AxSize用3bit表示,最多128字节
  • Regular Transaction 常规的事务
    • Regular_Transactions_Only 这个属性如果是TRUE,那么就只支持常规事务
    • AxLen 1,2,4,8,16
    • if AxLen > 1 , AxSize = data bus width
    • AxBurst = INCR or WRAP,没有FIXED
    • 地址是对齐的
  • 数据读写的结构
    • 实现混合的大小端数据的读写和非对齐传输(因为有字节选通,所以数据是按照字节为单位传的,没有大小端的问题,可以做到大小端混合的数据传输)
    • byte strobe 在VALID信号为低的时候保持低电平或者维持之前的信号不变
    • narrow transfers,就是用strobe选通。INCR和WRAP模式,不同传输次数之间的字节位置不同;FIXED模式下,字节位置固定。
    • 非对齐传输的两种方式:
      • 直接给非对齐的地址,从这个非对齐地址开始到对齐的边界算作一次传输
      • 用更低的对齐的地址,然后用strobe选通
    • 一次burst对应一次响应,有四种响应OKAY、EXOKAY、SLVERR、DECERR
  • AxCACHE
  • subordinate设备分为peripheral和memory
  • peripheral的信号可以简化,因为它实现的功能少
  • modifiable:
    • 一个事务可以拆分成多个事务
    • 多个事务可以合并成一个事务
    • 一个读事务可以读比需要的更多的数据
    • 一个写事务可以访问比需要的更多的地址空间,通过strobe选通
    • 在另外生成的事务中,AxADDR AxSIZE AxLEN AxBUREST可以被改写
    • AxLOCK和AxPROT不能被改写
  • 有了ID就可以有多个Outstanding的事务
  • RID和ARID对应
  • subordinate要对RID排序,这个排序的深度在设计subordinate的时候给定,manager没办法获得这个深度
  • interconnect会在每个master的ID前面加上master的ID,所以不用担心不同master的ID重复
  • exclusive访问:不支持其他master的访问

AXI4-Lite

  • 所有事务的AxLEN都是1
  • size都是数据位宽32/64
  • 不支持exclusive访问
  • non-modifiable
  • 虽然支持多个Outstanding的事务,但是subordinate可以合理地利用握手信号来限制这个

AXI4-Stream

  • 三种byte类型
    • Data byte:数据
    • Position byte: placeholder,不包含数据
    • Null byte:不包含任何数据和位置信息
  • 术语定义:
    • Transfer:一次VALID和READY的握手
    • Packet:多个Transfer
    • Frame:多个Packet
  • 四种数据流
    • Byte stream:data byte和null byte间隔
    • 只有data byte的对齐传输
    • 连续的data byte,在起始和结尾处补上position byte构成对齐传输
    • Sparse stream:data byte和position byte间隔
  • 信号
    • TSTRB和TKEEP:TSTRB区分data和position byte,TKEEP无效的是null byte
    • 时钟和复位同AXI4
    • 推荐tuser的bit数是字节个数的整数倍
  • 和AXI4的不同
    • AXI4不允许interleaving
    • AXI4-Stream没有最大的burst长度
    • AXI4-Stream的数据位宽任意
    • AXI4-Stream包含TID和TDEST指示源和目的信息
    • AXI4-Stream对TUSER的定义更具有操作性
    • AXI4-Stream多了TKEEP信号

创建自定义的AXI4-Lite外设

  Vivado的Tool标签下有一个选项就是“Create and Package New IPs”,点进去之后可以选择创建一个新的AXI4外设,然后给这个IP起个名字,可以先放到IP库里,然后在Block Design中调用它,再右键“Edit in IP Packager”。
在这里插入图片描述
  点击“Edit in IP Packager”之后,可以看到这个IP的顶层文件和一个它实例化的AXI4-Lite接口的模块。我们可以在这个模块中加入自己的设计,这里面一开始生成的代码大部分都不需要去改动,而且注释也都写得很清楚,每个always块都有注释。

// 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.
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     

  第一个always块是对awready和aw_en进行控制,注释也写了它“excepts no outstanding transactions”,也就是它只能逐个事务进行处理,只有在响应完成之后才能接收新的写数据。wready和awready是一样的,都会受到aw_en的控制,只有aw_en为高电平的时候,这两个ready才有可能置一;然后aw_en又只会在响应完成之后置高。

// 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_AWVALID, axi_wready and S_AXI_WVALID are asserted. Write strobes are used to
// select byte enables of slave registers while writing.
// 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.

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
		else if(slv_reg0[C_EN_BIT]) begin
			slv_reg0[C_EN_BIT] <= 1'b0;
		end
	end
end

  我给这个AXI4-Lite接口的外设分配了4个寄存器,上面这段代码是在AW和W通道都握手的情况下通过W通道往寄存器写数据,case语句选择寄存器,再根据WSTRB选择对应的字节。
  概括一下剩下的代码实现的功能。写响应只实现了响应OKAY,没有其他类型的响应。在ARVALID有效之后给出ARREADY,ARREADY只响应一个周期,同时锁存住读地址。在发现AR通道握手之后给出一个周期的RVALID信号。slv_reg_rden是AR通道握手,这个信号有效比RVALID提前一个周期,用这个信号作为使能,打一拍之后把数据送到RDATA上,正好RDATA和RVALID一起有效。
  用户逻辑设计的时候,可能只需要改上面的写寄存器的部分。根据寄存器中的值设计相应的逻辑对上面这部分代码没有影响。用户也可以增加自己的接口和参数定义,修改完之后记得改顶层的调用。

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
AXI4-Lite是一种简化版的AXI4协议,用于连接处理器和外设。下面是使用AXI4-Lite的基本步骤: 1.定义AXI4-Lite接口:定义AXI4-Lite接口时需要指定地址和数据宽度,如下所示: ```verilog module axi4_lite_interface ( input wire clk, input wire rst, // AXI4-Lite signals input wire [31:0] araddr, // Read address output reg [31:0] rdata, // Read data input wire arvalid, // Read address valid output reg arready, // Read address ready input wire [31:0] awaddr, // Write address input wire [31:0] wdata, // Write data input wire awvalid, // Write address valid output reg awready, // Write address ready input wire wvalid, // Write data valid output reg wready, // Write data ready input wire [1:0] wstrb, // Write strobe output reg bvalid, // Write response valid input wire bready // Write response ready ); ``` 2.实现状态机:使用状态机来处理读写请求和响应。在状态机的每个状态中,处理器可以采取不同的行动,例如准备好数据、等待数据、发送响应等。下面是一个简单的状态机示例: ```verilog reg [1:0] state, next_state; always @(posedge clk) begin if (rst) state <= IDLE; else state <= next_state; end parameter IDLE = 0, READ_ADDR = 1, READ_DATA = 2, WRITE_ADDR = 3, WRITE_DATA = 4, WRITE_RESP = 5; always @(*) begin case (state) IDLE: begin if (arvalid) next_state = READ_ADDR; else if (awvalid) next_state = WRITE_ADDR; else next_state = IDLE; end READ_ADDR: begin if (arready) next_state = READ_DATA; else next_state = READ_ADDR; end READ_DATA: begin if (bready) next_state = IDLE; else next_state = READ_DATA; end WRITE_ADDR: begin if (awready) next_state = WRITE_DATA; else next_state = WRITE_ADDR; end WRITE_DATA: begin if (wvalid) next_state = WRITE_RESP; else next_state = WRITE_DATA; end WRITE_RESP: begin if (bvalid) next_state = IDLE; else next_state = WRITE_RESP; end default: next_state = IDLE; endcase end ``` 3.实现读写逻辑:根据状态机的状态,实现读写逻辑。下面是一个读写逻辑示例: ```verilog reg [31:0] data_mem [0:255]; always @(posedge clk) begin // Read address if (state == READ_ADDR && arvalid && arready) begin rdata <= data_mem[araddr]; arready <= 1'b0; end else begin arready <= 1'b1; end // Write address and data if (state == WRITE_ADDR && awvalid && awready) begin data_mem[awaddr] <= wdata; wready <= 1'b1; awready <= 1'b0; end else if (state == WRITE_DATA && wvalid && wready) begin data_mem[awaddr] <= wdata; wready <= 1'b0; end else begin wready <= 1'b1; awready <= 1'b1; end // Write response if (state == WRITE_RESP && bready) begin bvalid <= 1'b1; end else begin bvalid <= 1'b0; end end ``` 以上是AXI4-Lite的基本使用方法,具体实现可以根据需要进行修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小裘HUST

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值