AXI_DMA IP核实战:24路并行数据高速存储方案

本文是AXI Direct Memory Access IP核在Direct Register模式下的实战例程,参考文档:

AXI Direct Memory Access IP核(1):AXI DMA深度解析_xilinx axi-dma-优快云博客

AXI Direct Memory Access IP核(2):AXI DMA --Direct Register模式仿真例程(xilinx example)_xilinx axi direct memory access-优快云博客

源代码:

【免费】AXI-DMAIP核实战:24路并行数据高速存储实战程序资源-优快云下载


1 概述

         在FPGA开发中,经常需要处理多路并行数据的采集与存储。本文将分享一个实际项目案例:将24路24位并行数据通过AXI_DMA高效地存入BRAM中。这个设计方案已经在我们的项目中稳定运行,希望能为有类似需求的开发者提供参考。

2 系统架构

整个系统由以下几个关键模块组成:

  • 数据产生模块:定时产生24路24位测试数据

  • 并行数据转AXIS模块:核心数据转换逻辑

  • AXI_DMA IP核:实现AXIS到AXI4总线的转换

  • AXI_VIP:用于配置和控制AXI_DMA

  • BRAM控制器:管理BRAM存储空间

3 详细设计说明

3.1 数据产生模块

       数据产生模块以50MHz时钟运行,每1us(50个时钟周期)产生一组完整的24路24位数据,主状态机控制流程如下,详细设计可以参考资源【免费】AXI-DMAIP核实战:24路并行数据高速存储实战程序资源-优快云下载

// 数据生成组合逻辑
always @(*) begin
    data_in_0 = {(24'h300000 + base_value[23:0]), (24'h200000 + base_value[23:0]), (24'h100000 + base_value[23:0]), (24'h000000 + base_value[23:0])};
    data_in_1 = {(24'h700000 + base_value[23:0]), (24'h600000 + base_value[23:0]), (24'h500000 + base_value[23:0]), (24'h400000 + base_value[23:0])};
    data_in_2 = {(24'hB00000 + base_value[23:0]), (24'hA00000 + base_value[23:0]), (24'h900000 + base_value[23:0]), (24'h800000 + base_value[23:0])};
    data_in_3 = {(24'hF00000 + base_value[23:0]), (24'hE00000 + base_value[23:0]), (24'hD00000 + base_value[23:0]), (24'hC00000 + base_value[23:0])};
    data_in_4 = {(24'h130000 + base_value[23:0]), (24'h120000 + base_value[23:0]), (24'h110000 + base_value[23:0]), (24'h100000 + base_value[23:0])};
    data_in_5 = {(24'h170000 + base_value[23:0]), (24'h160000 + base_value[23:0]), (24'h150000 + base_value[23:0]), (24'h140000 + base_value[23:0])};
end

// -------------- 控制状态机
reg [2:0] current_state,next_state;
always @(posedge data_clk or negedge data_rstn) begin
    if (!data_rstn) begin
        current_state <= IDLE;
    end else begin
        current_state <= next_state;
    end
end
// -------------- 主状态机
always @ (*) begin
    next_state = current_state;
    case(current_state)
    IDLE:begin
        next_state <= DATA_GEN;
    end
    DATA_GEN:begin
        next_state <= DATA_VALID;
    end
    DATA_VALID:begin
        next_state <= DATA_WAIT;
    end
    DATA_WAIT:begin
        if (cycle_counter == DATA_FRE-1) begin
            next_state <= DATA_GEN;
        end
        else begin
            next_state = current_state;
        end
    end
    default:begin
        next_state = IDLE;
    end
    endcase

3.2 并行数据转AXIS模块

这是整个设计的核心,内部主要包含两个状态机。

3.2.1 状态机1:接收并行数据并按通道写入FIFO

状态机设计:

  • IDLE状态:等待传输使能信号

  • COLLECT_V状态:等待数据valid信号

  • COLLECT_D状态:根据计数器将数据依次存入FIFO,如果存储的数据已经足够gpio_package_length,就返回IDEL状态,等待下一次传输。

关键逻辑实现:

/ -------------- 控制状态机
reg [2:0] current_state,next_state;
always @(posedge data_clk or negedge data_rstn) begin
    if (!data_rstn) begin
        current_state <= IDLE;
    end else begin
        current_state <= next_state;
    end
end
// ------------ 主状态机 
always @ (*) begin
    next_state = current_state;
    case(current_state)
    IDLE:begin
        if (data_wr_en_d0 & !data_wr_en_d1) begin
            next_state = COLLECT_V;
        end
    end
    COLLECT_V:begin
        if (word_valid_d0 & !word_valid_d1) begin  //全为1,上升沿检测
            next_state = COLLECT_D;
        end
        else begin
            next_state = current_state;
        end
    end
    COLLECT_D:begin
        if (Rec_count == gpio_packet_length_reg-1 ) begin
            next_state = IDLE;
        end
        else if (ch_count == CH_NUM-1) begin //共24个通道
            next_state = COLLECT_V;
        end
        else begin
            next_state = current_state;
        end
    end
    default:begin
        next_state = IDLE;
    end
    endcase
end

3.2.2 状态机2:从FIFO中取数据并转为AXIS

状态机设计:

  • IDLE状态:等待传输使能信号

  • UPDATE_LENGTH状态:取本次应该传输的数据量。

  • PREPARE_DATA状态:从FIFO中取数据

  • TRANSFER状态:转为AXIS总线形式,如果取数据量不足gpio_package_length,就返回PREPARE_DATA状态继续取数据,如果数据已经足够gpio_package_length,就返回IDEL状态,等待下一次传输使能。

关键逻辑实现:

// 状态寄存器
always @(posedge m_axis_clk or negedge m_axis_rstn) begin
    if (!m_axis_rstn) begin
        current_state_r <= IDLE;
    end else begin
        current_state_r <= next_state_r;
    end
end
// 状态转移逻辑
always @(*) begin
    next_state_r = current_state_r;
    case(current_state_r)
    IDLE:begin
        if (start_en_d0 & !start_en_d1) begin  // recieve start flag
            next_state_r = UPDATE_LENGTH;
        end
    end
    UPDATE_LENGTH:begin
        if (!fifo_rd_empty) begin  // 当有数据需要传输时,先更新数据量
            next_state_r = PREPARE_DATA;
        end
    end
    PREPARE_DATA:begin
        if (!fifo_rd_empty) begin // 
            next_state_r = TRANSFER;
        end
    end
    TRANSFER:begin
        if (axis_tready && axis_tvalid ) begin  
            if (trans_count == gpio_packet_length_reg - 1) begin  // data trans finish
                next_state_r = IDLE;
            end
            else begin
                next_state_r = PREPARE_DATA;
            end
        end
    end
    endcase
end

3.3  AXI_VIP模块配置AXI_DMA模块

3.3.1 AXI_DMA的GUI配置

其使用的是通用DMA模式,只使能了S2MM通道。

3.3.2 AXI_VIP仿真激励

配置AXI_DMA的传输使能、中断、目的地址、数据长度。详细可查看AXI Direct Memory Access IP核(1):AXI DMA深度解析_xilinx axi-dma-优快云博客

AXI Direct Memory Access IP核(2):AXI DMA --Direct Register模式仿真例程(xilinx example)_xilinx axi direct memory access-优快云博客

之后拉起start_en,即告诉系统可以开始传输数据了。

当接收到AXI_DMA传输完成的中断的时候,清中断,之后重新配置AXI_DMA,使能start_en,发起下一次传输。

4 仿真结果

从下图可以看出,每隔一段时间,就会收到来资源前端的有效数据。

4.1 关于写FIFO:

当ADMA配置完成之后,会拉起start_en;

当 数据转换模块检测到 start_en之后,开始检测有效数据

当 检测到有效数据valid之后,将数据写入fifo

当写入数据量,足够我们要求的数据量时(本次是1024个32bit),停止写入

以上为写FIFO的工作流程

4.2 关于读FIFO:

当ADMA配置完成之后,会拉起start_en;

当 数据转换模块检测到 start_en之后,开始等待FIFO有数据

当 检测到FIFO有数据之后,从FIFO中取数据

取够我们所需要的数据量之后,tlast拉起,停止取数

因为我们写入的数据量  和  取走的数据量是一致的,故我们可以看到到最后一拍的时候我们的fifo是empty的状态

4.3 仿真结论:

通过trans count我们也可以看出,我们的parallel_to_axis_converter,每次发出的数据均是1024个32bit,一个tlast信号。

我们再来看看ADMA端

ADMA端,1024个数据一个Tlast信号,之后数据转为AXI4存入ram,然后拉起adma的中断。

最后再来看看存入RAM的数据,因为我每次都是从0x000地址开始的,然后递增的方式存进去。

所以可以根据BRAM中的数据写入情况来查看。

<think> 我们正在讨论SystemVerilog中的包(package)导入问题。用户询问关于axi_vip_pkg和design_1_axi_vip_0_0_pkg的导入语句的使用和含义。 根据引用[1]中关于SystemVerilog语法的描述,package是一种将相关定义(如类型、函数、任务等)封装在一起的作用域,可以通过import语句在其他模块或接口中引用。 axi_vip_pkg和design_1_axi_vip_0_0_pkg都是包(package)的名称。其中: - axi_vip_pkg:可能是通用的AXI VIP(Verification IP)包,包含了用于验证AXI接口的通用组件、函数、任务等。 - design_1_axi_vip_0_0_pkg:可能是针对特定设计实例(design_1)中的某个AXI VIP实例(axi_vip_0_0)生成的包,通常包含该实例特定的定义或者配置。 在SystemVerilog中,导入包的目的是使用其中定义的内容。导入语句有两种常见形式: 1. 导入整个包的内容: ```systemverilog import axi_vip_pkg::*; ``` 这将使得该包中所有公共定义在当前作用域内可见。 2. 导入包中的特定项: ```systemverilog import axi_vip_pkg::my_type; import design_1_axi_vip_0_0_pkg::slv_agent_config; ``` 这样只导入指定的类型、变量或函数等。 用户可能在使用Xilinx的Vivado工具时遇到这些包。因为Xilinx的AXI VIP在生成时会根据实例名称生成特定的包(如design_1_axi_vip_0_0_pkg),其中可能包含该实例的配置对象、事务类型等。 引用[4]中展示了一个使用UVM(Universal Verification Methodology)的代码片段,其中使用了`uvm_do_with`宏,这通常用于测试平台中。在验证环境中,我们经常需要导入VIP包以使用其中定义的验证组件。 例如,在测试平台(testbench)中,我们可能会这样导入: ```systemverilog import axi_vip_pkg::*; import design_1_axi_vip_0_0_pkg::*; ``` 然后我们就可以使用这些包中定义的类型,例如: - 从axi_vip_pkg中定义的AXI事务类型(axi_transaction) - 从design_1_axi_vip_0_0_pkg中定义的特定代理配置(design_1_axi_vip_0_0_slv_agent_config) 需要注意的是,这些包通常是在编译VIP时自动生成的。因此,在编译用户测试平台之前,需要确保这些包已经被编译。 总结: - axi_vip_pkg:通用的AXI VIP包,提供通用的验证组件和事务模型。 - design_1_axi_vip_0_0_pkg:针对特定VIP实例的包,包含该实例的配置和适配。 - 使用import语句导入这些包,以便在测试平台中使用其中定义的类型、组件和函数。 §§相关问题§§ 1. SystemVerilog中package的组织结构是怎样的? 2. 如何创建自己的SystemVerilog包? 3. 在验证环境中使用VIP(Verification IP)的一般步骤是什么? 4. 如何处理多个包导入时的命名冲突? </think> ### SystemVerilog中包导入语句详解 在Verilog/SystemVerilog中,`import`语句用于引用预定义的包(package),这是模块化设计和验证环境构建的关键机制。 #### 1. **基本语法与含义** ```systemverilog import axi_vip_pkg::*; // 导入整个包的内容 import design_1_axi_vip_0_0_pkg::specific_item; // 导入包的特定项 ``` - **`axi_vip_pkg`**:通用AXI验证IP包,提供标准AXI协议验证组件(事务模型、驱动、监视器等)[^1][^3]。 - **`design_1_axi_vip_0_0_pkg`**:针对特定设计实例(如Vivado生成的`design_1`)的定制化VIP包,包含实例专属配置和接口定义[^4]。 - **`::*`**:通配符导入包内所有公开定义(类、函数、变量等)。 #### 2. **典型应用场景** **验证环境搭建**(参考引用[2][^4]): ```systemverilog import axi_vip_pkg::*; // 通用AXI组件 import design_1_axi_vip_0_0_pkg::*; // 设计专属配置 class my_test extends uvm_test; design_1_axi_vip_0_0_slv_agent_config slv_cfg; // 使用包内的配置类 task run_phase(uvm_phase phase); axi_transaction tx = new("tx"); // 使用通用事务类 tx.randomize(); ... endtask endclass ``` - **作用**:避免代码重复,直接调用VIP提供的预验证组件(如事务生成器、协议检查器)[^3][^4]。 #### 3. **底层原理** - **包封装**:通过`package`封装相关类和函数(如引用[4]中的`reg_pkg`): ```systemverilog package axi_vip_pkg; class axi_transaction; ... endclass // 事务模型 class axi_driver; ... endclass // 驱动组件 endpackage ``` - **模块化验证**:VIP包实现了AXI协议的心逻辑(握手信号`tready/tvalid`、数据流`tdata`等[^3]),用户只需关注测试场景。 #### 4. **使用要点** - **编译顺序**:先编译依赖包(如`axi_vip_pkg`),再编译导入它的模块。 - **作用域**:`import`需置于模块/类外部(全局作用域) - **命名冲突**:使用`::`显式指定包名(如`axi_vip_pkg::transaction` vs `user_pkg::transaction`)。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FPGA_小田老师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值