
1. 什么是Zynq AXI基础从“可编程逻辑处理器”融合体说起你刚接触Zynq看到“AXI”这个词反复出现在手册、IP核配置界面、Vivado Block Design连线端口里甚至在SDK的内存映射地址段注释中也冒出来——它不像UART或GPIO那样有直观的物理引脚对应也不像中断号那样能一眼看出触发逻辑。它更像一条看不见的高速公路系统安静地躺在Zynq芯片内部把PSProcessing System即ARM Cortex-A9双核处理器子系统和PLProgrammable Logic即FPGA可编程逻辑部分牢牢焊在一起。AXI不是某个外设而是Zynq能被称为“全可编程SoC”而非“FPGA加个ARM核”的底层骨架。没有AXIPS读不到PL里计数器的当前值PL也拿不到PS从网络收到的一帧图像数据——二者形同陌路。我第一次在某高校实验室调试一个图像直方图加速模块时就卡在这条“路”上PL侧逻辑仿真波形完美PS侧C代码编译无误但一运行Xil_In32()读回来的始终是0。查了三天寄存器地址、中断使能、缓存一致性最后发现根本没配对AXI GPGeneral Purpose接口的地址映射范围——相当于给汽车装好了发动机和方向盘却忘了修通往目的地的主干道。AXI就是那条必须提前规划、精确施工、全程验证的“片上高速总线”。它不炫技但一旦出错整个系统无声瘫痪它不抢镜却是所有Zynq加速、协处理、实时控制类项目的默认起点。如果你正打算用Zynq做视频流处理、工业通信网关、雷达信号预处理或者哪怕只是想让LED闪烁频率由ARM软件动态调节——那你绕不开AXI。这不是高级选修课是Zynq世界的“母语语法”。AXI的全称是Advanced eXtensible Interface由ARM公司定义专为片上系统SoC内部高带宽、低延迟、可扩展的数据传输而生。它和传统总线如AMBA AHB/APB最本质的区别在于“分离式事务”与“握手机制”读地址、读数据、写地址、写数据、写响应全部解耦成独立通道允许PS发起多个未完成请求outstanding transactionsPL侧可以乱序返回结果极大提升吞吐效率。举个生活化例子AHB像老式邮局——你寄一封信发请求必须等邮差确认送达收到响应才能寄下一封而AXI像现代快递分拣中心——你批量下单发多个地址请求不同快递员多通道并行取件、装车、派送系统自动归集签收单响应整体发货效率翻倍。Zynq的PS-PL通信带宽动辄几百MB/s没有这种架构根本撑不住。所以“Zynq AXI基础”绝非背几个信号名AWVALID、ARREADY之类就能应付的它是一套需要理解其哲学、掌握其建模、熟练其配置、敬畏其时序的完整工程能力。2. Zynq中AXI的三大核心角色GP/HP/ACP各司何职Zynq芯片内部并非只有一条AXI总线而是根据数据流向、性能要求、安全等级划分出三类关键AXI接口它们像城市里的不同道路系统GP是市区主干道HP是高速环线ACP是特种车辆应急通道。混淆它们的用途轻则性能瓶颈重则系统死锁。很多初学者在Vivado里拖出一个AXI DMA IP发现PS端连的是HP接口却硬往GP接口上接结果DMA跑不满一半带宽——问题根源不在DMA本身而在“路选错了”。2.1 AXI GPGeneral PurposePS与PL交互的“政务大厅”AXI GP接口是Zynq中最常用、最基础的PS-PL通信通道通常有4组GP0-GP3每组包含独立的读/写地址、数据、响应通道。它的设计目标是通用性与易用性适合中低带宽、低延迟敏感型控制与状态交互。典型场景包括PS通过Xil_Out32()向PL内寄存器写入配置参数如ADC采样率、滤波器系数PS读取PL侧状态机当前状态、计数器累加值、错误标志位PL向PS发起中断请求通过AXI GP的中断输出信号连接到PS的IRQ_F2P控制LED亮度、读取按键状态、切换显示模式等嵌入式常见操作。提示GP接口的地址空间由Vivado在Block Design中自动生成需在PS配置中勾选“Enable AXI GP interface”并在Address Editor里确认其Base Address如0x43C00000与Range通常64KB。这个地址就是你在C代码中Xil_Out32(0x43C00000, 0x1)操作的起点。务必注意该地址是PS端看到的虚拟地址经MMU转换后才访问PL物理资源因此若启用MMU且未配置正确页表读写会静默失败。GP接口的带宽上限受PS端AXI总线仲裁器限制实测连续突发传输Burst峰值约80-120 MB/s取决于Zynq型号与PS主频。它不支持Cache Coherency缓存一致性这意味着PS写入GP地址的数据可能滞留在L1/L2缓存中PL无法及时看到更新反之PL修改的寄存器值也可能被PS缓存旧值。解决方案是对GP寄存器操作必须使用Xil_Out32()/Xil_In32()这类带内存屏障memory barrier的函数或手动调用Xil_DCacheFlush()/Xil_DCacheInvalidate()强制刷缓存。这是我踩过最痛的坑之一——PL侧逻辑明明已将状态寄存器置1PS侧while(!Xil_In32(0x43C00004));却永远循环最后发现是L1缓存没刷新加一行Xil_DCacheInvalidate()立刻解决。2.2 AXI HPHigh PerformancePL访问DDR的“高速公路”AXI HP接口是Zynq中带宽最高的PS-PL通道通常有4组HP0-HP3直接连接到PS端的DDR控制器DDR PHY。它的核心使命是让PL像CPU一样高效、直接地读写外部DDR内存支撑大数据量搬运。典型场景包括AXI DMA引擎将PL采集的1080p视频帧约3MB/帧高速搬入DDR供PS处理PL实现的FFT加速器从DDR读取原始信号数据计算后将结果写回DDR指定区域视频编码器如H.264的码流缓冲区直接映射到HP地址空间PL侧编码完成即通知PS取走。HP接口的关键特性是支持64位数据总线、最大256-beat突发长度、以及最重要的——硬件级Cache Coherency仅限Zynq-7000系列中的某些HP端口需在PS配置中显式启用。这意味着当PL通过HP读取DDR中某块被PS缓存的数据时硬件会自动拦截请求确保PL拿到的是PS缓存中的最新副本反之亦然。这省去了大量手动缓存管理的麻烦。但代价是HP接口不支持PS主动发起对PL内部寄存器的读写它只服务于PL→DDR和DDR→PL的数据流。试图用Xil_Out32()向HP基地址写数据只会触发总线错误Bus Error或静默丢弃。注意HP接口的地址映射完全独立于GP。Vivado生成的HP Base Address如0x00100000对应的是DDR物理地址空间的起始偏移而非PL逻辑地址。例如若HP0 Base Address设为0x00100000Range为512MB则PL可通过AXI HP0访问DDR中0x00100000至0x20100000范围内的任意地址。这个地址必须与PS端malloc()分配的内存物理地址对齐否则DMA传输会出错。实践中我习惯用Xil_DmaPs_SimpleAlloc()申请DMA缓冲区并用Xil_DmaPs_GetPhysicalAddr()获取其物理地址再将其写入PL侧DMA的Source/Destination Address寄存器。2.3 AXI ACPAccelerator Coherency PortPL作为“协处理器”的特权通道AXI ACP接口是Zynq中最高权限、最低延迟的PS-PL通道仅1组直接接入PS的Snoop Control UnitSCU。它的存在意义是让PL逻辑在硬件层面成为ARM处理器的“一级协处理器”享有与CPU核心同等的缓存一致性待遇。典型场景极其有限但关键PL实现的硬件加速器如加密引擎、AI推理单元需要频繁、随机访问PS正在使用的同一块DDR数据如模型权重、输入特征图且要求毫秒级响应多核ARM系统中PL需保证对共享数据的原子性操作避免多核间缓存不一致导致计算错误。ACP的核心优势在于PL通过ACP发起的任何内存访问都会被SCU自动侦听snoop并实时同步所有CPU核心的L1/L2缓存。这意味着PS无需任何软件干预PL就能安全、高效地与CPU共享数据。但代价极高ACP占用PS端宝贵的SCU资源且Zynq-7000系列中仅Z-7045及以上高端型号才支持ACPZ-7010/20/30均不支持。对于绝大多数项目ACP是“奢侈品”GPHP组合已足够强大。我曾在一个金融风控算法加速项目中评估ACP最终因成本与复杂度放弃改用HP精细缓存管理性能损失不足5%但开发周期缩短两个月。3. AXI协议信号详解不只是背诵更要理解握手逻辑AXI协议定义了5个独立通道Write Address, Write Data, Write Response, Read Address, Read Data每个通道包含VALID/READY握手信号对。初学者常陷入“信号名背诵陷阱”以为记住AWVALID、WLAST、RRESP[1:0]就掌握了AXI。实际上AXI的灵魂在于VALID/READY的时序配合与数据流控制逻辑。就像两个人传递一摞文件一个人VALID1说“我准备好交给你了”另一个人READY1说“我现在能接”只有当双方同时为1文件数据才真正移交。任何一方为0传输就暂停不丢数据、不报错这是AXI可靠性的基石。3.1 写事务Write Transaction全流程拆解以PS向PL写入一个32位控制字为例完整流程如下忽略ID、LEN等细节聚焦核心写地址阶段AW ChannelPS驱动awaddr目标地址如0x43C00000、awvalid1PL检测到awvalid且自身awready1时采样awaddrawvalid与awready同时拉高即完成地址握手。此时PL已知“要往哪写”。写数据阶段W ChannelPS驱动wdata待写数据、wstrb字节使能0xF表示4字节全写、wvalid1PL检测到wvalid且wready1时采样wdata与wstrb完成数据握手。注意wvalid与awvalid可异步即地址发完后数据可延迟发送PL需缓存地址等待数据。写响应阶段B ChannelPL完成数据写入内部寄存器后驱动bresp0x0OKAY、bvalid1PS检测到bvalid且bready1时采样bresp握手完成。bvalid与wvalid之间无固定时序约束PL可在数据写入后任意时刻发出响应。实操心得在PL侧Verilog中实现AXI Lite简化版AXI用于寄存器访问从机时我最初将awready、wready、bready全部恒置为1认为“反正快”。结果PS端出现总线超时Bus Timeout。排查发现bvalid发出后PS需时间采样若bready立即为1PS可能在bvalid建立前就采样导致响应丢失。正确做法是bready需在bvalid稳定至少1个周期后再拉高形成可靠的建立时间Setup Time。这个细节在Xilinx PG080文档第12页有明确时序图但极易被忽略。3.2 读事务Read Transaction全流程拆解以PS读取PL状态寄存器为例读地址阶段AR ChannelPS驱动araddr如0x43C00004、arvalid1PL采样araddr后arready1完成地址握手。读数据阶段R ChannelPL根据araddr从内部寄存器读取数据驱动rdata、rresp0x0OKAY、rvalid1PS检测到rvalid且rready1时采样rdata完成数据传输。rvalid与arvalid同样可异步。关键点在于读数据rvalid的发出时机完全由PL决定。PL可以立即返回零等待周期也可插入多个等待周期如等待ADC转换完成。这赋予了PL极大的灵活性但也要求PS端驱动必须能容忍任意长度的等待。Xilinx提供的axi_lite_slave_v3_0IP核默认支持可配置等待周期但在自定义逻辑中若忘记在rvalid前加入必要延时会导致PS读到无效数据。3.3 AXI Burst突发传输机制如何榨干带宽AXI真正的威力在于Burst突发传输它允许单次地址请求后连续传输多个数据拍beat避免重复发送地址开销。Burst类型有INCR递增最常用、WRAP回绕用于Cache Line、FIXED固定地址。以INCR为例PS发送awaddr0x1000、awlen34拍则PL需依次写入地址0x1000、0x1004、0x1008、0x100C的数据。Burst长度LEN与大小SIZE共同决定单次突发的总字节数Total Bytes (LEN 1) * (2^SIZE)。例如awlen78拍、awsize38字节/拍则单次突发传输64字节。Zynq HP接口支持最大awlen255256拍结合64位总线单次突发可达2KB极大提升大块数据搬运效率。常见误区认为awlen越大越好。实测发现当awlen超过3233拍时某些PL侧AXI总线仲裁器会出现优先级反转导致小包控制指令被大包数据阻塞。我的经验是控制类传输用awlen0单拍大数据流用awlen7或158或16拍平衡效率与实时性。Vivado HLS生成的AXI Master IP其MAX_BURST_LENGTH参数务必与实际需求匹配否则综合后可能插入过多流水线增加延迟。4. Vivado中AXI实战从Block Design到SDK驱动的完整链路纸上谈兵终觉浅绝知此事要躬行。下面以一个真实项目——“PL侧实现PWM发生器PS端动态调节占空比与频率”为例完整走一遍Zynq AXI开发闭环。此项目覆盖GP接口配置、地址映射、Verilog从机编写、Vivado综合实现、SDK C驱动开发、软硬件协同调试是AXI基础的黄金练兵场。4.1 Block Design搭建四步精准配置添加Zynq Processing System IP在Vivado IP Integrator中拖入ZYNQ7 Processing System双击打开配置向导。关键设置PS-PL Configuration→AXI Non-secure Enable勾选GP0启用AXI GP0接口MIO Configuration→UART 0勾选UART 0用于SDK串口调试输出Clock Configuration→PL Fabric Clocks设置FCLK_CLK0为100MHz供PL逻辑使用点击Run Block Automation自动生成PS基础配置。添加AXI GPIO IP作为PWM控制寄存器拖入AXI GPIOIP双击配置IP Configuration→All Options→GPIO Width设为3232位控制字AXI Interface→Enable Tri-state取消勾选我们只用输出即PS写PLAXI Interface→Enable Interrupt勾选后续可扩展中断功能此IP本质是一个预封装的AXI Lite从机内部已实现完整的VALID/READY握手逻辑省去手写Verilog的繁琐。连线与地址分配将ZYNQ7 Processing System的S_AXI_GP0端口连接到AXI GPIO的S_AXI端口右键ZYNQ7 Processing System→Validate Design确保无错误打开Address Editor可见axi_gpio_0自动分配地址如0x43C00000Range为64KB。记录此地址C代码中将使用。生成输出产品Generate Output Products→ 全选生成IP Catalog、Synthesis、Implementation所需文件Create HDL Wrapper→ 选择Let Vivado manage wrapper and auto-updateGenerate Bitstream等待综合、实现、生成bit文件。4.2 SDK中C驱动开发三行代码控制PWMVivado生成bit后启动Vitis原SDK创建新Application Project如pwm_control选择Hello World模板。修改src/helloworld.c#include xparameters.h #include xil_io.h #include xil_printf.h // 定义PWM控制寄存器地址来自Address Editor #define PWM_CTRL_REG_ADDR 0x43C00000 int main() { init_platform(); // 初始化平台串口等 xil_printf(PWM Control Demo Start\r\n); // 步骤1初始化PWM写入0x00000000关闭输出 Xil_Out32(PWM_CTRL_REG_ADDR, 0x00000000); // 步骤2设置占空比50%bit15:0 0x8000频率1kHzbit31:16 0x0000 // 假设PL逻辑约定低16位占空比0-0xFFFF高16位频率分频系数 u32 pwm_config (0x0000 16) | (0x8000 0); // 高16位0低16位0x8000 Xil_Out32(PWM_CTRL_REG_ADDR, pwm_config); // 步骤3使能PWM输出bit31 1 pwm_config | (1UL 31); Xil_Out32(PWM_CTRL_REG_ADDR, pwm_config); xil_printf(PWM Enabled: 1kHz, 50%% Duty\r\n); cleanup_platform(); return 0; }关键说明Xil_Out32()函数内部已包含__asm__ volatile (dsb ::: memory)内存屏障指令确保写操作立即提交到AXI总线不会被编译器优化或CPU乱序执行打乱。若自行用指针操作如*(volatile u32*)PWM_CTRL_REG_ADDR value;必须手动添加Xil_DCacheFlush()否则PL可能收不到数据。这是新手最常栽跟头的地方。4.3 PL侧Verilog逻辑进阶手写AXI Lite从机若需更高定制性如支持读取PWM当前计数值需手写AXI Lite从机。以下为精简核心框架基于Xilinx PG100// axi_pwm_slave.v module axi_pwm_slave #( parameter integer C_S_AXI_DATA_WIDTH 32, parameter integer C_S_AXI_ADDR_WIDTH 16 )( input wire S_AXI_ACLK, input wire S_AXI_ARESETN, // Write Address Channel input wire [C_S_AXI_ADDR_WIDTH-1:0] S_AXI_AWADDR, input wire S_AXI_AWVALID, output wire S_AXI_AWREADY, // Write Data Channel input wire [C_S_AXI_DATA_WIDTH-1:0] S_AXI_WDATA, input wire S_AXI_WVALID, output wire S_AXI_WREADY, // Write Response Channel output wire [1:0] S_AXI_BRESP, output wire S_AXI_BVALID, input wire S_AXI_BREADY, // Read Address Channel input wire [C_S_AXI_ADDR_WIDTH-1:0] S_AXI_ARADDR, input wire S_AXI_ARVALID, output wire S_AXI_ARREADY, // Read Data Channel output wire [C_S_AXI_DATA_WIDTH-1:0] S_AXI_RDATA, output wire [1:0] S_AXI_RRESP, output wire S_AXI_RVALID, input wire S_AXI_RREADY, // User logic signals output reg [31:0] pwm_ctrl_reg, // 连接到PWM IP input wire pwm_counter_val // 从PWM IP读取的当前计数值 ); // 地址解码0x00 - ctrl_reg, 0x04 - counter_val localparam ADDR_CTRL 4h0; localparam ADDR_CNT 4h1; reg [C_S_AXI_ADDR_WIDTH-1:0] awaddr_latched; reg [C_S_AXI_ADDR_WIDTH-1:0] araddr_latched; reg write_en; reg read_en; // AW Channel Handshake always (posedge S_AXI_ACLK) begin if (!S_AXI_ARESETN) begin S_AXI_AWREADY 1b0; awaddr_latched h0; end else begin if (S_AXI_AWVALID !S_AXI_AWREADY) begin S_AXI_AWREADY 1b1; awaddr_latched S_AXI_AWADDR; end else if (S_AXI_AWVALID S_AXI_AWREADY) begin S_AXI_AWREADY 1b0; // 单次握手后拉低 end end end // W Channel Register Write always (posedge S_AXI_ACLK) begin if (!S_AXI_ARESETN) begin pwm_ctrl_reg h0; write_en 1b0; end else begin if (S_AXI_WVALID S_AXI_WREADY) begin case (awaddr_latched[3:0]) ADDR_CTRL: begin pwm_ctrl_reg S_AXI_WDATA; write_en 1b1; end default: ; endcase end end end // AR Channel Handshake always (posedge S_AXI_ACLK) begin if (!S_AXI_ARESETN) begin S_AXI_ARREADY 1b0; araddr_latched h0; end else begin if (S_AXI_ARVALID !S_AXI_ARREADY) begin S_AXI_ARREADY 1b1; araddr_latched S_AXI_ARADDR; end else if (S_AXI_ARVALID S_AXI_ARREADY) begin S_AXI_ARREADY 1b0; end end end // R Channel Data Drive assign S_AXI_RDATA (araddr_latched[3:0] ADDR_CNT) ? {24h0, pwm_counter_val} : {24h0, pwm_ctrl_reg}; assign S_AXI_RRESP 2b00; // OKAY // RVALID控制在AR握手完成后延迟1周期发出RVALID reg rvalid_delay; always (posedge S_AXI_ACLK) begin if (!S_AXI_ARESETN) begin rvalid_delay 1b0; S_AXI_RVALID 1b0; end else begin if (S_AXI_ARVALID S_AXI_ARREADY) begin rvalid_delay 1b1; // AR握手成功准备发RVALID end else if (rvalid_delay S_AXI_RREADY) begin S_AXI_RVALID 1b0; // RREADY拉高后RVALID拉低 rvalid_delay 1b0; end else if (rvalid_delay !S_AXI_RREADY) begin S_AXI_RVALID 1b1; // RREADY未拉高保持RVALID end end end // B Channel Response assign S_AXI_BRESP 2b00; assign S_AXI_BVALID (S_AXI_WVALID S_AXI_WREADY); // W握手成功即发B响应 endmodule此代码实现了标准AXI Lite协议重点在于S_AXI_AWREADY/S_AXI_WREADY/S_AXI_ARREADY的时序控制确保握手可靠S_AXI_RVALID的延迟发出满足建立时间要求地址解码逻辑清晰支持多寄存器映射使用S_AXI_ARESETN异步复位符合Zynq PS复位规范。将此文件添加到Vivado工程替换之前的AXI GPIO IP重新综合实现即可获得完全自主可控的PWM控制逻辑。5. AXI调试避坑指南那些手册不会写的血泪教训AXI调试是Zynq开发中最耗时的环节问题往往隐蔽且难以复现。以下是我在多个项目中总结的高频问题与独家排查技巧全是实测有效的“野路子”比官方文档更接地气。5.1 总线超时Bus Timeout不是代码错是时序没对齐现象PS端Xil_Out32()或Xil_In32()后程序卡死在函数内部或返回错误码XST_FAILURE。原因分析AXI协议要求VALID与READY信号必须满足建立/保持时间Setup/Hold Time。Zynq PS端输出的awvalid、wvalid等信号其边沿位置受PS时钟相位影响。若PL侧逻辑尤其是跨时钟域同步未严格满足时序约束PS可能在PL未准备好时就发出VALID导致握手失败PS端触发超时保护。排查技巧用ChipScopeVivado ILA抓PS端S_AXI_GP0信号重点看awvalid与awready是否曾同时为1。若从未同时为1说明PL侧awready逻辑有误如复位未释放、状态机卡死检查PL时钟域确认S_AXI_ACLK是否确实连接到PS提供的FCLK_CLK0100MHz而非其他时钟。曾有项目误接FCLK_CLK1200MHz导致PL逻辑时序违例awready无法及时响应插入两级同步器若awready由PL内部状态机生成务必用两级DFF同步到S_AXI_ACLK域避免亚稳态。这是Xilinx官方强烈推荐但新手常忽略的步骤。5.2 数据错位Data Misalignment字节使能WSTRB惹的祸现象PS写入0x12345678PL侧寄存器读到0x00345678高字节丢失。原因AXI协议中wstrbWrite Strobe信号指示哪些字节有效。32位总线对应4位wstrbwstrb4b1111表示4字节全写wstrb4b0001表示只写最低字节。若PL侧逻辑未正确解析wstrb或PS端驱动如Xil_Out32()在特定条件下生成了非全字节使能就会导致部分字节被PL忽略。解决方案在PL侧Verilog中必须显式用wstrb掩码写入操作always (posedge S_AXI_ACLK) begin if (write_en) begin case (awaddr_latched[3:0]) ADDR_CTRL: begin if (wstrb[0]) pwm_ctrl_reg[7:0] wdata[7:0]; if (wstrb[1]) pwm_ctrl_reg[15:8] wdata[15:8]; if (wstrb[2]) pwm_ctrl_reg[23:16] wdata[23:16]; if (wstrb[3]) pwm_ctrl_reg[31:24] wdata[31:24]; end endcase end end同时在SDK中永远使用Xil_Out32()/Xil_In32()操作32位寄存器避免Xil_Out16()混用确保wstrb恒为4b1111。5.3 缓存污染Cache Pollution为什么读到的总是旧值现象PL侧逻辑已将状态寄存器更新为0x1PS端while(Xil_In32(addr) ! 0x1);无限循环。原因PS的ARM Cortex-A9拥有L1指令/数据缓存及L2统一缓存。Xil_In32()读取的可能是缓存中的旧副本而非AXI总线上PL刚刚写入的新值。终极解决方案硬件层面在PS配置中将GP接口地址空间如0x43C00000的内存属性设为Device-nGnRnE非缓存、非缓冲、非可执行。在Vivado中ZYNQ7 Processing System→PS-PL Configuration→AXI Non-secure Enable→GP0→Memory Attributes→ 选择Device-nGnRnE。此设置强制CPU绕过缓存直连AXI总线彻底杜绝污染软件层面备用若必须用缓存如大块数据则每次读前调用Xil_DCacheInvalidateRange((u32)addr, 4);每次写后调用Xil_DCacheFlushRange((u32)addr, 4);。但此法开销大仅作保底。5.4 地址映射错乱Vivado生成的地址为何不生效现象Vivado Address Editor显示axi_gpio_0地址为0x43C00000但PS端写入此地址PL无反应。原因Zynq PS的地址映射分两层——物理地址Physical Address与虚拟地址Virtual Address。Vivado生成的是物理地址而Linux系统若运行Linux中应用程序看到的是虚拟地址需通过/dev/mem或mmap()映射。但即使裸机Bare Metal环境若PS配置中AXI GP0未勾选或Address Editor未点击Apply生成的地址也不会写入PS的AXI地址解码器。快速验证法在SDK中添加以下代码读取PS端AXI GP0的地址解码寄存器位于0xF8007100u32 gp0_base Xil_In32(0xF8007100); // GP0 Base Address Register u32 gp0_range Xil_In32(0xF8007104); // GP0 Range Register xil_printf(GP0 Base: 0x%08x, Range: 0x%08x\r\n, gp0_base, gp0_range);若输出0x00000000说明PS配置中未启用GP0若输出0x43C00000则证明地址已正确加载。此法比翻手册快十倍。6. AXI性能优化实战从100MB/s到350MB/s的跃迁AXI性能不是玄学而是可量化