zynq7000- linux平台 PS读写PL测试

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", &reg_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", &reg_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;
}
相关推荐
BD_Marathon7 小时前
【Linux】awk命令
linux·运维·服务器
Z22ZHaoGGGG7 小时前
verilog中数据跨时钟处理方法
单片机·嵌入式硬件·fpga开发·自动化
前端世界8 小时前
Linux 防火墙实战:用 firewalld 配置 External/Internal 区域,实现 NAT 内网共享上网
linux·服务器·网络
陌路208 小时前
操作系统(6)虚拟内存-缓存工具-页表(2)
linux
林一百二十八9 小时前
Win11配置VMware-workstation以及Ubuntu环境
linux·运维·ubuntu
FPGA_小田老师9 小时前
FPGA基础知识(十):深入理解建立时间与保持时间违例
fpga开发·时序约束·建立时间违例·保持时间违例
铜豌豆_Y9 小时前
嵌入式Linux驱动开发之I2C子系统(3)--I2C子系统框架
linux·运维·驱动开发
LNN202210 小时前
Qt creator +Valgrind检测内存泄漏(linux)
linux·开发语言·qt
0wioiw010 小时前
Ubuntu(④Mysql)
linux·mysql·ubuntu