AXI4-Lite总线:寄存器读写、地址映射、响应信号、与AXI4-Stream协同
AXI4-Lite,说白了就是AXI协议的“轻量版”。我刚开始接触Xilinx DMA Bridge的时候,总觉得AXI4-Lite和AXI4-Full差不多,不就是少了几根信号线吗?实际做下去才发现,这里头的门道还挺多。
这一章咱们就聚焦AXI4-Lite。它不处理大数据块搬运,专管控制类的读写——比如配DMA的描述符、查状态寄存器、启动或停止传输。你想想看,如果我们用AXI4-Stream搬运数据是“修高速路”,那AXI4-Lite就是这条路上的“收费站”和“指示牌”。
寄存器读写:一次一笔,规规矩矩
AXI4-Lite的读写在时序上非常规整。每一次事务(transaction)只传一笔数据,地址位宽固定(通常是32位),数据位宽也固定(32位或64位)。没有突发传输(burst),没有乱序,没有交织。说白了,就是个“老实人”。
我个人习惯把AXI4-Lite的读写流程拆成两个阶段:
- 地址阶段:主机(Master)把地址、控制信号扔到总线上
- 数据阶段:从机(Slave)给出数据(读),或者主机写入数据(写)
写事务会多一个响应阶段,从机用BRESP告诉主机:“我收到了”或者“我拒绝”。
地址映射:芯片里的“门牌号”
地址映射是硬件设计里绕不开的活。每个从机(Slave)在系统地址空间里占据一段连续区间。主机发来的地址,经过地址译码器(Address Decoder)判断,落到哪个从机的管辖范围,就把对应的片选(Chip Select)信号拉高。
我在项目中遇到过一个问题:两个从机的地址区间有重叠,结果某个地址写操作同时落到了两个设备上,数据冲突,系统跑飞。排查了大半天才找到。
地址映射时,我一般会列一张表:
| 从机名称 | 基地址 | 地址范围 | 寄存器数量 |
|---|---|---|---|
| DMA控制寄存器 | 0x44A0_0000 | 0x1000 | 16 (32-bit each) |
| 状态寄存器 | 0x44A0_1000 | 0x1000 | 8 |
| 中断控制寄存器 | 0x44A0_2000 | 0x1000 | 4 |
地址宽度我习惯用32位。为什么?因为这个DMA Bridge通常挂在ARM或MicroBlaze的32位总线上,统一宽度省事。如果地址宽度不一样,还得加地址转换逻辑,麻烦。
嗯,这里要注意:地址映射不能留“空洞”。我曾经在一个设计里给从机分配了0x1000的范围,但实际寄存器只用了前几个地址,后面的地址没做处理,结果软件误写到了“空洞”,读回来的数据全是X态。后来我老老实实地把未使用的地址空间也做了默认响应(返回OKAY,但忽略写数据)。
响应信号:不是每个请求都能成功
AXI4-Lite的响应信号有固定的编码。做硬件的人常说“握手信号”,说的就是VALID/READY这对信号配合上响应码。
响应码有两种:OKAY和DECERR,写操作还多一个SLVERR。我记得刚开始做设计时,总觉得都是OKAY就完事了,结果有一次从机因为内部FIFO满了,设备无法响应写请求,但我没做SLVERR的处理,结果数据丢了,软件端毫无察觉。
下面是我常用的响应处理原则:
- 地址落在合法范围内,功能正常→返回OKAY(2'b00)
- 地址落在范围内,但从机内部出错(如FIFO满)→返回SLVERR(2'b10)
- 地址落在范围外→返回DECERR(2'b11)
响应信号的时序也关键。当主机发起读请求(ARVALID拉高),从机必须在有限周期内给出ARREADY,并在RVLAID拉高时带上RRESP。不能无限期等待,否则主机可能会超时。
与AXI4-Stream协同:两条腿走路
DMA Bridge的核心价值就在于把AXI4-Lite和AXI4-Stream结合起来。一个管控制,一个管数据,两条腿走路。
我画过一张图,每次讲课都会拿出来用——
这张图讲的是啥呢?
- CPU通过AXI4-Lite写控制寄存器——比如设置源地址、目的地址、传输长度
- CPU再写一个“启动”寄存器,AXI4-Stream Master就开始从源端拉数据
- 数据搬运过程中,CPU可以通过AXI4-Lite读状态寄存器——检查传输进度、是否出错
- 传输完成,Stream Master触发中断,CPU再通过Lite读完成状态
你看,Lite管的是“脑子”,Stream管的是“手脚”。两者缺一不可。
我习惯在设计AXI4-Lite从机时,顺带留几个“调试寄存器”。比如:记录最后一次异常地址的寄存器、记录Stream通道FIFO深度的寄存器、记录中断次数的计数器。这些寄存器不影响正常功能,但在调板时特别好用。有时候一个bug,看几眼调试寄存器就能定位。
对了,还有一个细节:AXI4-Lite的地址阶段和数据阶段是分离的。对于写事务,地址先到,数据后到,从机需要把地址和数据对齐。我用的方法是设计一个简单的地址队列(FIFO),先把地址存起来,等数据到了再配对处理。这个队列深度我设成4,一般够了。但如果你遇到高频率的写操作,队列深度不够会导致写入失败,这时可以适当加深。
这一章的内容就到这。AXI4-Lite不是大数据搬运的主角,但它确保了主角能按剧本演出。不做那张图的管理者,整个系统就是一盘散沙。