目录
- AXI是什么
- AXI是如何工作的
- AXI-Lite定义
- AXI-Lite的关键特性
- AXI-Lite信号列表
- AXI-Lite信号时序
- 时钟和复位
- 握手机制
- 写请求通道(AW)
- 写数据通道(W)
- 写响应通道(B)
- 读请求通道(AR)
- 读数据通道(R)
- * 握手的依赖关系(重要)
- 写事务依赖
- 读事务依赖
- AXI-Lite的FPGA实现
- Xilinx自定义IP核
- 从机
- 主机
- 仿真
- 手搓
- Alex Forencich代码解读
- axil_adapter顶层参数 & 端口
- axil_adapter_wr
AXI是什么
AXI为ARM AMBA的一部分,是一种微控制总线。
2003年,AMBA3.0发布,其中包含第一版AXI;
2010年,AMBA4.0发布,其中包含第二版AXI,称为AXI4;
时至今日,AXI已经有了AXI5版本,可以在ARM官方网站下载到源文件,可自行下载:
ARM官网中各版本AMBA文件
AXI包括三种接口形式:
名称 | 特点 |
---|---|
AXI4 | 高性能的内存映射需求 |
AXI4-Lite | 简单的、低吞吐量的内存映射通信(例如,控制寄存器和状态寄存器) |
AXI4-Stream | 用于高速流数据 |
AXI是如何工作的
AXI是内存映射接口,在一个地址周期内,允许至多256个数据的传输,无论是AXI4还是AXI4-Lite接口,都有五个不同的通道。
数据可以同时在主机和从机之间的两个方向上移动,并且数据传输的大小可以变化。AXI4中的限制是最多256个数据传输的突发事务。AXI4-Lite只允许每个事务传输1个数据。主从机之间数据读取、写入的通道架构如下所示。
需要注意的事,上面虽是两张图,只是为了方便区分读、写操作对应的通道,实际上主、从机应该同时具有5个通道,主机发起读写请求,从机响应主机的读写请求。
AXI-Lite定义
AXI-Lite的关键特性
- 所有的传输突发长度均为1
- 所有的数据访问都使用数据总线的全宽度(只能是32-bitsZ或64-bits)
- 所有的访问都是不可修改的,不可缓冲的
- 不支持独占访问
AXI-Lite信号列表
前缀解析
AW:Address Write,写请求通道,对应图中写地址通道
W : Write,写数据通道
B: 写响应通道
AR: Address Read,读地址通道
R: Read,读数据通道
AXI-Lite信号时序
时钟和复位
握手机制
同前缀的 VALID/READY信号为一组握手信号,握手协议用来传输地址、控制信息、数据等内容。
这种双向的协议,能够保证主、从机都能够控制传输速率。源端产生VALID信号,指示现在的地址、控制信息、数据都是有效的;目的端产生READY信号,指示现在可以接收信息了,传输发生在二者均为HIGH的时候。
主、从机之间的接口,输出->输入接口之间,一定不能有组合逻辑路径
READY和VALID信号,谁先“伸出手”都无所谓,READY可以在先,VALID可以在先,也可以同时。
下图是同时伸手的时序样例:
写请求通道(AW)
控制信号如下两个。
主机只有在要产生有效请求时才能拉高AWVALID信号,一旦拉高,就得保持到从机拉高AWREADY后的时钟上升沿。
AWREADY的默认值是高是低都可以,推荐默认值为高。
当 AWREADY为高是,从机必须能够接收提供给他的所有有效请求。
不建议AWREADY 默认为LOW是因为,它强制传输至少需要两个周期,一个用于拉高AWVALID,另一个用于拉高AWREADY。
AWPROT:可用于保护内存免受意外事务的影响,默认给0
地址和信息都在这个通道传输了。
写数据通道(W)
控制信号有两个:WREADY和WVALID
WSTRB:就像一个开关,指定所传输的WDATA中,哪个字节是有效信息,所以其位宽为DATA_WIDTH / 8,为1时,对应的字节有效,为0时,对应的字节无效。
写响应通道(B)
控制信号有两个:BREADY和BVALID
BRESP:指示当前的写操作是否成功,为0表示成功
读请求通道(AR)
控制信号如下两个。
信号和写请求介绍类似。
ARPROT:可用于保护内存免受意外事务的影响,默认给0
读数据通道(R)
控制信号有两个:RREADY和RVALID
RRESP:读响应信息合并在了读数据通道内,所以,相比于写操作,读操作少了一个响应通道。
其值为0时,表示读取成功。
* 握手的依赖关系(重要)
---------->
键尾 箭头
单箭头:箭头处的信号,可以在键尾处信号之前或之后拉高。
双箭头:箭头处的信号,必须在键尾处信号之后拉高。
伸手 == 拉高
写事务依赖
- 主机在拉高AWVALID或WVALID之前,不能等待从机拉高AWREADY或WREADY,这适用于事务中的每次写数据传输。想写,必须主机先伸手,从机可以等,也可以先伸手(对应后面两条)
- 从机在拉高AWREADY或WREADY之前,可以等待AWVALID或WVALID
- 从机可以在AWVALID、WVALID之前或之后,拉高AWREADY或WREADY
- 从机必须等待四个双箭头键尾信号拉高后,再拉高BVALID
- 从机在拉高BVALID之前,一定不能等待主机拉高BREADY,也就是写响应时,从机必须先伸手
- 主机可以等BVALID信号,不必先伸手,当然,也可以先伸手
总的来说,对于AWVALID 和 AWREADY,WVALID和WREADY这两个握手,从主机的角度看,他不能等从机,主观上要先伸手;从机的角度看,他等不等主机都行,主观上不必先伸手。客观上,主机先伸手,从机先伸手的情况都是存在的。
对于BVALID和BREADY这个握手,就和上面的描述颠倒过来,从机主观上必须先伸手,主机不必先伸手,但是谁先伸手的情况客观上都是存在的。
图A3.5,把和BVALID有关的箭头都拿掉,可以看到一个简单的握手关系,这能说明AXI总线地址数据独立、分离的特性,支持不对齐数据传输的特性(即顺序上,不必先地址再数据)
读事务依赖
- 在拉高ARVALID之前,主机一定不能等从机拉高ARREADY。想读,主机主观上必须先伸手,从机主观上不必等主机伸手,但是客观上,谁先伸手的情况都存在。
- 从机拉高表示数据有效的RVALID信号,一定要在两个双箭头键尾的信号拉高之后。
- 从机一定在拉高RVALID之前,主观上一定不能等主机拉高RREADY,即从机必须先伸手,主机主观上不必先伸手,客观上,谁先伸手的情况都存在。
总的来说,读事务中的两个握手,对于ARVALID 和 RREADY,从主机的角度看,他不能等从机,主观上要先伸手;从机的角度看,他等不等主机都行,主观上不必先伸手。客观上,主机先伸手,从机先伸手的情况都是存在的。RVALID 和 ARREADY反过来理解即可。额外的,RVALID受ARVALID和ARREADY影响。
图A3.6可以从图A3.5中简化出来,一起理解就好了。
理解依赖关系,是理解FPGA AXI-Lite逻辑时序的基础,上面解释依赖关系时,反复提到的“主观上”一词,主要体现在代码逻辑上
AXI-Lite的FPGA实现
Xilinx自定义IP核
从机
从机代码可以使用Xlinx官方提供的自定义IP自动化产生
芯片型号XC7Z020CLG400-1,Vivado2018.3
创建 Block Design —> Tools —>Create and Package New IP
按照所需配置选好,在Block Design中找到IP
这就是Xilinx官方自动生成的AXI-Lite Slave代码,用户可以修改这个文件,增加自己的逻辑,修改完保存后,更新这个自定义IP,就能在Block Design用了。
主机
同样的方式可以生成主机代码,只需要在自定义IP核配置界面写Master即可。
主机和从机生成的模块如上图所示,修改Block Design,如下图,验证无误后,生成顶层。
仿真
编写顶层的tb文件,给时钟和复位。
`timescale 1ns / 1ps
module tb_axi_lite();
reg clk ,rst_n ,tx;
always #5 clk = !clk;
design_1_wrapper design_1_wrapper_u0
(
.m00_axi_aclk_0 (clk ),
.m00_axi_aresetn_0 (rst_n ),
.m00_axi_init_axi_txn_0 (tx )
);
initial begin
clk = 0;
rst_n = 0;
tx = 0;
#500
@(posedge clk);
rst_n = 1;
end
initial begin
pause();
end
task pause();
begin
wait(rst_n);
repeat(5)@(posedge clk);
tx <= 1;
@(posedge clk)
tx <= 0;
end
endtask
endmodule
下图可以看到,一个txn的脉冲,可以触发4次写和4次读,这种仿真方法可以最快速便捷的观察AXI-Lite波形,无需自己写代码。
写请求、写数据、写响应三个通道的波形一起看
读图信息:
- 地址跳变为0 4 8 12,这是因为数据为4 Byte,地址跳变间隔需要以数据字节数为准
- 图中展示的是地址和数据相位对齐,其实可以不对齐,AXI是支持的
- 写地址和写数据通道波形,能体现出主机的“主动性”,即先伸手
- 写响应通道能体现出从机的“主动性”,即先伸手
- BVALID是在四个信号拉高后,才拉高的,对应了前面介绍的依赖关系
读请求、读数据、两个通道的波形一起看
RVALID时序,也能够对应上面的依赖关系。
一些信息接口,如STRB PORT ESP等,可以自行添加看
ESP为0,对应写成功,读成功
STRB为F,表示所有字节均为有效数据
PORT 写是0,读是1,写是非特权访问,读是特权访问,不太重要,关系内存访问权限
手搓
这里推荐学习Alex Forencich大神的源码,事半功倍
Github AXI代码链接
本文中涉及的官方PDF下载
var code = "ad2dfd79-083f-4117-a87f-7126cf0201d1"
Alex Forencich代码解读
READM.md中,可以看到AXI-Lite的文件架构,顶层即为axil_adapter,内部例化两个模块,分别是axil_adapter_wr和axil_adapter_rd。
axil_adapter顶层参数 & 端口
27-29行,是基本的一些配置,29行代码规范了良好的编程习惯,先定义,再使用,否则会报错。
顶层parameter参数,结合前面对AXI-Lite的学习,理解不难,地址位宽和数据位宽都是32,STRB用来指定哪些字节是有效数据,故按照字节计算,是除8。顶层参数中的数据位宽和STRB,主机从机独立的,地址位宽是统一的,这里独立设置的用意?
从机的接口,和前面的手册截图一致。
主机的接口,和前面的手册截图一致。
axil_adapter_wr
主体框架:
- if else框架里边嵌套两个1段式状态机,用组合逻辑实现,里面写了10筐逻辑
- 一段时序逻辑always块,里面写了一筐逻辑
状态机分为 STATE_IDLE , STATE_DATA , STATE_RESP共3段
当前状态为state_reg,下一个状态为state_next
EXPAND:如果主机来的STRB,大于从机所需的STRB,需要拉高EXPAND信号
SEGMENT_COUNT:EXPAND拉高后,需要算出STRB大了多少,这个是倍数值
这里按照主机、从机都是32-bits先看,可知 EXPAND=0 , SEGMENT_COUNT=1,则进入 if (SEGMENT_COUNT == 1 || EXPAND) 条件中嵌入的状态机,对应源码189~237行
状态机 case(state_reg)
如果写请求的ready和valid尚未握手,就保持IDLE
如果握手成功,状态跳转至 STATE_DATA,同时设置了很多尾缀next的信号,带有该尾缀的信号表示,该信号下一个状态应该是什么样的
写请求握手后:
- awready信号拉低
- s_axil_awaddr存下来,传给Master的 m_axil_awaddr_next,以备给下游设备
- s_axil_awprot存下来,传给Master的 m_axil_awprot_next,以备给下游设备
- m_axil_awvalid_next拉高,以备和下游设备握手
- 从机写准备 赋值 主机写有效的取反
该模块叫 adapter,转接器,在系统中其呈上启下的纽带作用,并没有自己的处理,也就是说,该模块会把上游发给他的指令,转发给下游;在上游模块面前,他是从机,在下游模块面前,他是主机。本质上就是个听旨宣旨的。理解了该模块的功能,对理解程序是有帮助的。
数据阶段:
如果和上游之间写数据的valid和ready尚未握手,就保持数据状态,否则进行一系列处理。
如果和上游握手成功
- 拉低wready信号,取消握手
- 上游传过来的wdata和wstrb信号,转存给从机,以备往下游发
- 拉高给下游的wvalid信号
- 给下游的beady信号 赋值 上游bvalid信号取反
- 跳转至写响应阶段
响应阶段:
如果和下游之间写响应的valid和ready尚未握手,就保持响应状态,否则进行一系列处理。
握手后:
- 给下游的响应valid信号拉低,取消握手
- 下游来的bresp信号,传给上游
- 给上游的bvalid信号拉高
- 给上游的写请求ready信号 赋值 下游来的写请求valid信号取反
- 跳转回IDLE状态
上游、下游位宽相等的情况下的状态机中,组合逻辑就是这些
下面是时序逻辑部分,同步复位结构,把所有next后缀的变量,赋值给不带后缀的变量,表示当前状态被新状态更替。