zynq7000- linux平台 PS读写PL测试
ZYNQ PL使用自定义AXI slave 模块 :
BD如下:
FPGA代码简单,可在vivado 自定义 AXI slave ip上的代码更改即可

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

linux上运行程序。代码可以自行改善。下面代码功能有:
1、遍历 PL寄存器,自定义测试寄存器个数
2、自定义测试轮数,指定对某寄存器读写
等等
注意:
vivado上BD分配的物理地址要和下面代码上能够对上。
#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;
}
