一、Xilinx 几种 IP 核区别
| IP 核名称 | 核心特点 | 用户接口 | 开发难度 | 适用场景 |
| 7 Series Integrated Block for PCI Express | 最基础的 PCIe 硬核,提供物理层和数据链路层 | AXI4-Stream TLP 包 | 最高,需处理 TLP 包 | 需深度定制 PCIe 通信,对资源敏感的项目 |
| AXI Memory Mapped To PCI Express | 桥接 IP,将 PCIe 接口转换为 AXI 接口 | AXI4 内存映射 | 中等,类似操作总线 | FPGA 需主动读写主机内存,平衡效率与灵活性 |
| DMA/Bridge Subsystem for PCI Express (XDMA) | 集成 DMA 引擎,提供一站式解决方案 | AXI4 (另有 AXI-Lite 等辅助接口) | 最低,官方提供驱动 | 高速数据批量传输(如采集卡),追求开发效率 |
注意:
- 硬件平台限制:不同系列的 Xilinx FPGA(如 7 系列、UltraScale、Versal)支持的 PCIe 代数和通道数可能不同。在选择 IP 核前,请务必确认您的 FPGA 型号是否支持所需的 PCIe 配置(如 Gen3 x8)。
- 资源与性能权衡:XDMA 虽然易用,但会消耗更多的 FPGA 逻辑资源。在资源紧张的设计中需要仔细评估。
- 驱动与系统集成:使用 XDMA 或 AXI Memory Mapped IP 时,通常需要配合驱动。XDMA 虽有官方驱动,但据反馈在某些版本下可能存在一些小问题,需要留意。
二、PCIE 介绍及使用
(一)版本说明
工具:vivado2016.4 芯片:xc7vx690tffg1157-2 PCIE:Virtex-7 FPGA Gen3 Integrated Block for PCI Express v4.3(前面介绍的 7 Series Integrated Block for PCI Express 比较老)
(二)数据信号区别
(1)哪几组
分为四组如下:
s_axis_rq_tdata s_axis_rq_tuser
m_axis_rc_tdata m_axis_rc_tuser
m_axis_cq_tdata m_axis_cq_tuser
s_axis_cc_tdata s_axis_cc_tuser
(2)都是啥
1)举例说明
举个例子,PC 传输一组波形数据到 fpga,并且告诉 FPGA 将波形数据从 DAC 发出去,同时将发出去的信号用 ADC 采集回来通过 FPGA 传输给 PC。这个系统包含三个主要功能:
- PC → FPGA:传输 DAC 波形数据
- FPGA:控制 DAC 输出并同步 ADC 采集
- FPGA → PC:上传 ADC 采集数据
阶段一:PC 传输波形数据和命令到 FPGA
使用接口: m_axis_cq_tdata, m_axis_cq_tuser
过程:
- 命令下发:
// PC 写 FPGA 的命令寄存器 // m_axis_cq_tdata: MWr TLP,地址=命令寄存器,数据=START_DAC // m_axis_cq_tuser: bar_id=0, addr=0x1000(命令寄存器地址)
- 波形数据传输:
// PC 连续写 FPGA 的波形缓冲区 // m_axis_cq_tdata: MWr TLP,地址=波形缓冲区,数据=波形样本 // m_axis_cq_tuser: bar_id=1, addr=波形缓冲区偏移地址
- FPGA 侧处理:
always @(posedge clk) begin
if (m_axis_cq_tvalid && m_axis_cq_tready) begin
// 解析 TLP 头,判断是命令还是数据
case (m_axis_cq_tuser[84:80]) // bar_id
5'b00000: cmd_reg <= m_axis_cq_tdata[31:0]; // 命令寄存器
5'b00001: wave_buffer[write_addr] <= m_axis_cq_tdata; // 波形数据
endcase
end
end
阶段二:FPGA 执行 DAC 输出和 ADC 采集
FPGA 内部逻辑:
// DAC 控制状态机
always @(posedge clk) begin
case (state)
IDLE: if (cmd_reg == START_DAC) state <= PLAY_WAVE;
PLAY_WAVE: dac_data <= wave_buffer[read_addr]; read_addr <= read_addr + 1;
if (read_addr == WAVE_LENGTH) state <= IDLE;
endcase
end
// 同步 ADC 采集
always @(posedge clk) begin
if (dac_valid) begin
// 与 DAC 输出同步
adc_buffer[write_adc_addr] <= adc_data; write_adc_addr <= write_adc_addr + 1;
end
end
阶段三:FPGA 上传采集数据到 PC
使用接口: s_axis_rq_tdata, s_axis_rq_tuser
过程:
- DMA 传输准备:
// PC 预先通过配置寄存器告诉 FPGA 主机内存的物理地址 // m_axis_cq_tdata: MWr TLP,地址=DMA 目标地址寄存器
- 采集数据上传:
// FPGA 发起存储器写请求 // s_axis_rq_tdata: MWr TLP,地址=主机内存,数据=ADC 采集数据 // s_axis_rq_tuser: sop=1/0, eop=1/0, bar_id=0
- FPGA 侧 DMA 引擎:
// DMA 状态机
always @(posedge clk) begin
if (dma_start && s_axis_rq_tready) begin
s_axis_rq_tvalid <= 1'b1;
s_axis_rq_tdata <= {tlp_header, adc_buffer[dma_addr]};
s_axis_rq_tuser <= {sop, eop, 3'b000}; // bar_id=0
if (eop) dma_addr <= 0; else dma_addr <= dma_addr + 1;
end
end
2)8 个数据链路的使用分析
(此处省略图片,参考官方文档查看信号时序)
3)哪些是必要的
必须使用的 4 个核心链路: m_axis_cq_tdata/user:下行通道,接收命令和波形数据 s_axis_rq_tdata/user:上行通道,上传采集数据
推荐使用的 2 个辅助链路: s_axis_cc_tdata/user:状态查询响应
可以暂不使用的 2 个链路: m_axis_rc_tdata/user:留作未来功能扩展
4)tuser 到底是个啥
以下行通道为例:
当 FPGA 接收来自 PC 的命令和波形数据时,m_axis_cq_tuser 提供了解析 TLP 包所需的全部元数据。
i. 主要字段详解:
// m_axis_cq_tuser 结构 (位宽因 IP 核版本而异,通常~180bit)
{
// 1. 包边界控制 (最重要的字段)
sop, // [0] Start of Packet - TLP 开始
eop, // [1] End of Packet - TLP 结束
// 2. 地址空间识别
bar_id, // [5:0] 来自哪个 BAR 空间
bar_hit, // [6:0] BAR 命中指示
// 3. 字节级控制
first_be, // [3:0] 第一个 DW 的字节使能
last_be, // [3:0] 最后一个 DW 的字节使能
// 4. 传输控制
discontinue, // 提前终止指示
tkeep, // 字节有效掩码 (独立信号,有时在 tuser 中)
// 5. 事务信息
is_sop0_ptr, // SOP0 指针
is_sop1_ptr, // SOP1 指针
// 6. 错误和状态
err, // 错误指示
parity // 奇偶校验
}
ii. 实际应用示例:
// 解析主机写请求的 Verilog 代码片段
always @(posedge clk) begin
if (m_axis_cq_tvalid && m_axis_cq_tready) begin
// 检查 TLP 包开始
if (m_axis_cq_tuser[0]) begin // sop=1
// 解析 BAR 空间,决定数据路由
case (m_axis_cq_tuser[5:3]) // bar_id 部分位
3'b000: begin // BAR0 - 命令寄存器
cmd_address <= m_axis_cq_tdata[63:32];
current_transfer <= COMMAND;
end
3'b001: begin // BAR1 - 波形数据缓冲区
wave_address <= m_axis_cq_tdata[63:32];
current_transfer <= WAVE_DATA;
end
endcase
// 保存字节使能信息
first_byte_enable <= m_axis_cq_tuser[15:12];
end
// 处理数据
if (current_transfer == WAVE_DATA) begin
// 根据 byte_enable 处理数据
process_wave_data(m_axis_cq_tdata, m_axis_cq_tuser[15:12], // first_be
m_axis_cq_tuser[19:16]); // last_be
end
// 检查 TLP 包结束
if (m_axis_cq_tuser[1]) begin // eop=1
current_transfer <= IDLE;
generate_completion_if_needed();
end
end
end
iii. 关键字段应用场景
(此处省略图片,参考官方文档查看信号定义)
iv. 重要注意事项
- 位宽变化:不同 Xilinx IP 核版本和 PCIe 配置下,tuser 信号的位宽和字段位置可能不同。
- 文档参考:必须查阅对应的 PG195 或 PG213 文档获取确切格式。
- 字节序:注意 PCIe 的小端字节序,数据在总线上可能需要重新排列。
- 对齐要求:first_be/last_be 用于处理非双字对齐的访问。
三、IP 如何配置
(一)配置参数
由于是仿真,基本都是默认。
(此处省略配置界面截图)
(二)配置完成
(此处省略配置完成截图)
四、仿真
Open IP Example design......Run Simulation......Run Behavioral Simulation,注意:180 多 us 才出结果。
(此处省略仿真结果截图)
五、参考
Virtex-7 FPGA Gen3 Integrated Block for PCI Express v4.3 Product Guide (PG023)


