菜鸟一枚,最近也学习了关于 AXI 总线的相关知识。基于 PYNQ 编写了一个简单的 AXI 主从控制(牵涉到 DDR3 的读写)。
设计目的
设计出以下一个通过 AXI 总线连接的简单片上系统。包含以下部分:
PL 端逻辑
PL 端实现四个模块包括:
-
寄存器堆
寄存器堆主要是对指令等控制信息进行片上存储。具体的指令将由 PS 端写入。对于寄存器堆来说,其相当于 slave,而 PS 端的 jupyter 服务器相当于 master。使用的总线是 AXI Lite 总线(棕色的大箭头)。 -
控制端
控制端主要做的是将寄存器堆送来的指令进行译码,进而从寄存器堆中取得各种配置信息,产生控制信号(主要是对 DRAM 的访存操作,相当于是 SDRAM 控制器)。
寄存器堆与控制端要进行连线。
-
内存读处理(read)
该模块主要负责处理对DRAM的读请求与接收到数据的处理。主要负责实现 AXI FULL 总线的相关读逻辑。内部有一个读请求的 FIFO 队列。 -
内存写处理(write)
该模块主要负责处理对DRAM的写请求与写数据的处理。主要负责实现 AXI FULL 总线的相关写逻辑。内部有一个写数据请求的FIFO队列。
控制端与读写请求处理模块(DRAM)是 master 与 slave 的关系。即控制端通过产生相应的访存请求信号,进而令读写请求模块进行访存的相应操作。简而言之,读写请求模块其实就是 AXI 总线的访存接口,其内部实现了 AXI 总线相应的握手机制,我们可以通过这两个模块在片上进行 ddr 的读写控制。故读写请求模块要挂在 AXI 总线上(绿色大箭头)。
下图中红色的框即为上面所说的 PL 端逻辑模块的系统框图。我们可以用 HDL 把模块实现好之后封装成 IP 核,写好输入输出端口,就可以挂在 AXI_Interconect 和 AXI register slice IP 核上并且连接到 ZYNQ 硬核上。进而编写 PS 端程序。

可能有人要问,为什么绿色的箭头有5条,而棕色有2条?其实这就是 AXI 总线的内部机制,下图记录了 AXI 读写的时序图。可以很清楚地看到读数据时,只需要两个通道即可,而写数据则需要三条通道,所以说对于访存请求处理的两个模块共需要5条导线。而寄存器堆其实也是需要3条线,只是图中省去了,因为在 pynq 里我们可以很方便的对寄存器地址进行判断(4的倍数)。

PS 端程序设计
接下来是软件方面的设计。我们知道,为了发挥 zynq 系列的优势,我们将通讯密集型的应用放在 CPU 上——即指令相关的控制信息的写入或预先对 ddr 数据的写入。
由于本篇博文是基于 pynq 的,故不牵涉到 sdk 编程(其实两者原理相同)。
- 对 DDR 的读写
由于我们使用的是 pynq,其中已经封装好了我们需要用到的相应 API,只需调用即可!在这一步里我们主要调用以下 API:
from pynq import Xlnk
xlnk.cma_array(shape=(),dtype=np.float16)
该函数返回一个 numpy 数组,相当于在 DRAM 里申请了一段大小为 shape 的空间,然后可以自由地对这一段空间进行读写操作。
- 对寄存器堆的写入
我们在 jupyter 服务器下可以很方便的对寄存器堆进行读写!只需提前定义好相应的寄存器地址即可。在这一步里我们主要调用以下 API:
from pynq import MMIO
ctrl = MMIO(0x40000000, 0x1000)# 开辟一块区域可供用户读写,主要是对寄存器(slave)的读写
ctrl.write(reg_addr,<

本文介绍了一种基于AXI总线的片上系统设计,使用PYNQ平台实现DDR3的读写控制。设计包括寄存器堆、控制端、内存读写处理模块,并详细说明了AXI总线的内部机制。软件方面,通过调用PYNQ提供的API,实现了对DDR的读写及寄存器堆的控制。
最低0.47元/天 解锁文章
9874





