ZYNQ PL使用自定义AXI slave 模块 :
BD如下:
FPGA代码简单,可在vivado 自定义 AXI slave ip上的代码更改即可

系统制作完,直接在虚拟机上编译好可执行文件,在板子上运行即可:
./axilite -l 100
运行结果

linux上运行程序。代码可以自行改善。下面代码功能有:
1、遍历 PL寄存器,自定义测试寄存器个数
2、自定义测试轮数,指定对某寄存器读写
等等
注意:
vivado上BD分配的物理地址要和下面代码上能够对上。
c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <stdint.h>
#include <string.h>
#include <signal.h>
#include <time.h>
#define AXI_BASE_ADDRESS 0x40000000 // 根据实际情况修改
#define MAP_SIZE 0x1000 // 4KB 映射空间
#define REGISTER_COUNT 34 // 测试的寄存器数量
static volatile uint32_t *axi_base = NULL;
static int mem_fd = -1;
static int running = 1;
// 信号处理函数,用于优雅退出
void signal_handler(int sig)
{
printf("\n收到信号 %d,正在退出...\n", sig);
running = 0;
}
// 映射物理内存到用户空间
int map_axi_memory(void)
{
// 打开 /dev/mem 设备
mem_fd = open("/dev/mem", O_RDWR | O_SYNC);
if (mem_fd < 0) {
perror("打开 /dev/mem 失败");
return -1;
}
// 映射物理内存
axi_base = mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, AXI_BASE_ADDRESS);
if (axi_base == MAP_FAILED) {
perror("内存映射失败");
close(mem_fd);
return -1;
}
printf("成功映射物理内存:\n");
printf(" 物理地址: 0x%08X\n", AXI_BASE_ADDRESS);
printf(" 虚拟地址: %p\n", axi_base);
printf(" 映射大小: 0x%X (%d KB)\n", MAP_SIZE, MAP_SIZE / 1024);
return 0;
}
// 取消内存映射
void unmap_axi_memory(void)
{
if (axi_base != NULL && axi_base != MAP_FAILED) {
munmap((void*)axi_base, MAP_SIZE);
axi_base = NULL;
}
if (mem_fd >= 0) {
close(mem_fd);
mem_fd = -1;
}
}
// 读取寄存器值
uint32_t read_register(int reg_index)
{
if (axi_base == NULL || reg_index >= MAP_SIZE / 4) {
printf("错误: 无效的寄存器索引 %d\n", reg_index);
return 0;
}
uint32_t value = axi_base[reg_index];
printf("读取 寄存器[%d]: 地址=%p, 值=0x%08X\n",
reg_index, &axi_base[reg_index], value);
return value;
}
// 写入寄存器值
void write_register(int reg_index, uint32_t value)
{
if (axi_base == NULL || reg_index >= MAP_SIZE / 4) {
printf("错误: 无效的寄存器索引 %d\n", reg_index);
return;
}
axi_base[reg_index] = value;
printf("写入 寄存器[%d]: 地址=%p, 值=0x%08X\n",
reg_index, &axi_base[reg_index], value);
}
// 循环读写测试
void read_write_loop_test(int test_count)
{
printf("\n=== 开始循环读写测试,共 %d 轮 ===\n", test_count);
int error_count ;
int error_flag ;
error_flag = 0;
for (int i = 0; i < test_count && running; i++) {
error_count = 0;
printf("\n--- 第 %d 轮测试 ---\n", i + 1);
// 写入测试数据
for (int reg = 1; reg < REGISTER_COUNT; reg++) {
uint32_t write_value = 0x1000 * (i + 1) + 0x100 * reg + 0xAB;
write_register(reg, write_value);
usleep(1000); // 1ms 延迟
}
// 读取验证
for (int reg = 1; reg < REGISTER_COUNT; reg++) {
uint32_t read_value = read_register(reg);
uint32_t expected = 0x1000 * (i + 1) + 0x100 * reg + 0xAB;
if (read_value == expected) {
printf("寄存器[%d] ✅ 验证成功\n", reg);
} else {
error_count = error_count + 1;
printf("寄存器[%d] ❌ 验证失败: 读取=0x%08X, 期望=0x%08X\n",
reg, read_value, expected);
}
usleep(1000); // 1ms 延迟
}
// 每10轮显示进度
if ((i + 1) % 10 == 0) {
printf("已完成 %d/%d 轮测试\n", i + 1, test_count);
}
sleep(1); // 每秒一轮
printf ("读写错误数量 是: %d\n" ,error_count);
if (error_count > 0) {
error_flag = 1;
printf("=== AXI SLave 读写在第 %d轮出现问题 推出测试 ===\n",test_count);
break;
}
}
printf("=== 数据错误标志 error_flag = %d ===\n",error_flag);
printf("=== 循环读写测试完成 ===\n");
}
// 递增模式测试
void incremental_pattern_test(void)
{
printf("\n=== 开始递增模式测试 ===\n");
for (int i = 0; i < 16 && running; i++) {
uint32_t pattern = 0x11111111 * i;
printf("\n模式 %2d:\n", i);
// 写入不同模式的数据
write_register(0, pattern);
write_register(1, ~pattern);
write_register(2, pattern >> 16);
write_register(3, pattern << 16);
// 读取显示
printf("读取结果: ");
for (int reg = 0; reg < REGISTER_COUNT; reg++) {
printf("0x%08X ", read_register(reg));
}
printf("\n");
sleep(1);
}
printf("=== 递增模式测试完成 ===\n");
}
// 交互式测试模式
void interactive_test(void)
{
printf("\n=== 进入交互式测试模式 ===\n");
printf("命令说明:\n");
printf(" r <索引> - 读取寄存器\n");
printf(" w <索引> <值> - 写入寄存器\n");
printf(" s - 显示所有寄存器状态\n");
printf(" q - 退出\n");
char command[256];
while (running) {
printf("\n> ");
fflush(stdout);
if (fgets(command, sizeof(command), stdin) == NULL) {
break;
}
// 解析命令
if (strncmp(command, "r", 1) == 0) {
int reg_index;
if (sscanf(command + 1, "%d", ®_index) == 1) {
read_register(reg_index);
} else {
printf("用法: r <寄存器索引>\n");
}
}
else if (strncmp(command, "w", 1) == 0) {
int reg_index;
uint32_t value;
if (sscanf(command + 1, "%d %x", ®_index, &value) == 2) {
write_register(reg_index, value);
} else {
printf("用法: w <寄存器索引> <十六进制值>\n");
}
}
else if (strncmp(command, "s", 1) == 0) {
printf("当前寄存器状态:\n");
for (int i = 0; i < REGISTER_COUNT; i++) {
uint32_t value = axi_base[i];
printf(" 寄存器[%d]: 0x%08X\n", i, value);
}
}
else if (strncmp(command, "q", 1) == 0) {
break;
}
else {
printf("未知命令。使用 r, w, s, 或 q\n");
}
}
}
// 显示使用说明
void print_usage(const char *program_name)
{
printf("用法: %s [选项]\n", program_name);
printf("选项:\n");
printf(" -l <次数> 循环测试次数 (默认: 50)\n");
printf(" -i 交互式模式\n");
printf(" -p 递增模式测试\n");
printf(" -a <地址> AXI基地址 (十六进制, 默认: 0x%08X)\n", AXI_BASE_ADDRESS);
printf(" -s <大小> 映射大小 (十六进制, 默认: 0x%X)\n", MAP_SIZE);
printf(" -h 显示此帮助信息\n");
printf("\n示例:\n");
printf(" %s -l 100 # 循环测试100次\n", program_name);
printf(" %s -i # 交互式模式\n", program_name);
printf(" %s -a 0xA0000000 # 指定基地址\n", program_name);
}
int main(int argc, char *argv[])
{
int test_count = 10;
int interactive_mode = 0;
int pattern_mode = 0;
uint32_t base_addr = AXI_BASE_ADDRESS;
size_t map_size = MAP_SIZE;
// 解析命令行参数
int opt;
while ((opt = getopt(argc, argv, "l:ipa:s:h")) != -1) {
switch (opt) {
case 'l':
test_count = atoi(optarg);
break;
case 'i':
interactive_mode = 1;
break;
case 'p':
pattern_mode = 1;
break;
case 'a':
base_addr = strtoul(optarg, NULL, 16);
break;
case 's':
map_size = strtoul(optarg, NULL, 16);
break;
case 'h':
print_usage(argv[0]);
return 0;
default:
print_usage(argv[0]);
return 1;
}
}
// 注册信号处理
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
printf("AXI Lite PL寄存器测试应用程序\n");
printf("基地址: 0x%08X, 映射大小: 0x%zX\n", base_addr, map_size);
// 映射内存
if (map_axi_memory() < 0) {
return 1;
}
// 根据模式执行测试
if (interactive_mode) {
interactive_test();
} else if (pattern_mode) {
incremental_pattern_test();
} else {
read_write_loop_test(test_count);
}
// 清理资源
unmap_axi_memory();
printf("应用程序退出\n");
return 0;
}