Reactive Ports for the AXI Slave VIP
AMD AXI从设备VIP(验证IP)中“Reactive Ports”的使用方法,这是一种让能够自定义从设备对读命令响应行为的高级功能。
核心概念:反应式端口
用途:当您不希望从设备使用预定义的内存模型(如
axi_slv_mem_agent)自动回复读数据,而是想完全由您自己的验证代码来控制和提供读响应数据时,应使用此功能。前提:必须使用
axi_slv_agent,而非自带内存模型的axi_slv_mem_agent。
操作步骤与原理
接收命令:在从设备代理的读取驱动中,调用
get_rd_reactive()任务。这是一个阻塞调用,它会等待并捕获主设备发送过来的读命令事务。填充响应:在获取到该读事务后,您需要根据自己的测试逻辑,填充其响应信息,主要包括:
数据:通过类似
fill_payload()的函数填充要返回的读数据。用户信号:通过
fill_ruser()填充。时序:通过
fill_beat_delay()为每个数据节拍设置延迟。
发送响应:调用
send()任务,将您填充好的响应事务发送回AXI总线,从而完成本次读操作。此调用也是阻塞的。
关键代码结构与注意事项
必须使用循环:由于
get_rd_reactive()和send()都是阻塞调用,并且您需要持续处理所有到来的读命令,必须将它们包裹在一个initial begin forever begin ... end end的无限循环块中。这是确保驱动能持续工作的标准模式。自定义响应逻辑:在
fill_payload等步骤中,您可以实现任意的数据生成行为,例如返回特定模式的数据、模拟错误响应、或根据地址进行复杂计算,这为协议测试和故障注入提供了极大灵活性。
How to Receive Read Data
获取读取数据主要有两种途径:
通过VIP的监视器接收:这是一种被动监听的方式,可以捕获到所有经过AXI总线的事务数据。
2. 通过主代理的读取驱动接收:这是一种主动发起并获取的方式,主设备主动发起读事务后,从返回的响应中提取数据。
方法一:从监视器接收数据
此方法适用于监控总线上的所有读写活动。
操作步骤:
获取监视器事务:从主代理或从代理的
item_collected_port端口接收到监视器事务。判断事务类型:检查事务中的
cmd类型。若为
XIL_AXI_READ,则后续获取的是读数据。若为
XIL_AXI_WRITE,则获取的是写数据。
提取数据:使用事务的以下API获取数据:
get_data_beat(beat_index):获取指定节拍(beat)的数据。get_data_block():获取整个事务的完整数据块(最大4KB)。
方法二:从读取驱动接收数据
此方法适用于主设备主动发起读操作并需要处理返回数据。
操作步骤:
创建读事务:通过主代理的读取驱动创建读事务句柄。
配置事务:随机化该事务,或使用API(如
set_addr(),set_len())手动设置特定地址、突发长度等。关键设置:必须调用
set_driver_return_item_policy(),将策略设置为XIL_AXI_PAYLOAD_RETURN或XIL_AXI_CMD_PAYLOAD_RETURN,以便驱动能返回包含数据的响应事务。发送与等待:用读取驱动发送该事务,然后使用
wait_rsp()等待响应返回。从响应中提取数据:从驱动返回的响应事务中,使用
get_data_beat()或get_data_block()检查读取到的数据。
重要注意事项:数据表示格式
API返回的数据格式与物理总线上的表示不同,这是关键易错点。
对齐方式:
get_data_beat和get_data_block返回数据时,总是将有效字节对齐到数据的低位字节(LSB),未使用的高位字节则填充为零。与物理总线的区别:例如,在一个32位数据总线、每次传输1字节(subsize)的突发读操作中,只有
get_data_beat返回值的最后8位(一个字节)是有效数据。而在物理总线RDATA上,这1字节数据可能出现于32位中的任意一个字节通道。
总结与建议
选择方法:若需监控总线流量,用监视器方法;若需主设备控制读操作并处理数据,用驱动方法。
注意数据对齐:处理数据时,务必牢记VIP API的数据对齐规则,这与实际总线信号不同,进行数据比对或检查时需要相应处理。
Write Transaction Methods
一、 写事务的三种方法
您可以根据需要选择以下任一种方法来发起写事务:
方法一:创建、随机化并发送(通用推荐)
步骤:
从主代理的写驱动创建事务对象。
对事务进行随机化(或手动约束)。
通过驱动发送该事务。
关键特性:此API调用默认是非阻塞的。如果您需要获取事务的响应信息(如BRESP),必须在发送前调用
set_driver_return_item_policy()来设置返回策略。代码示例:
方法二:使用单行任务(传统简单)
说明:使用一个集成的任务(如
AXI4_WRITE_BURST),在一行调用中传递所有事务参数(地址、数据、ID、突发类型等)。关键特性:这是一个阻塞调用,任务会一直等待,直到从设备返回写响应(BRESP)后才返回。
适用场景:适用于简单、直接的写操作,代码紧凑。
方法三:通过API手动设置命令与数据(精确控制)
步骤:
创建事务对象。
使用
set_write_cmd()API 手动设置命令相位(地址、突发长度等)。使用
set_data_block()设置整个数据块,或使用set_data_beat()循环设置每个节拍的数据。发送事务。
适用场景:当您需要对事务的每一个字段进行精确、非随机的控制时使用。
Read Transaction Methods
二、 读事务的两种主要方法
发起读事务也有对应的两种方式:
方法一:创建、随机化并发送(通用推荐)
步骤与写事务方法一完全类似,区别在于从读驱动创建和发送事务。
同样需要注意:默认是非阻塞的,如需获取返回的读数据和读响应,必须提前设置
set_driver_return_item_policy()。代码示例:
方法二:使用单行任务(传统简单)
使用
AXI4_READ_BURST任务,这是一个阻塞调用,会等待读数据和读响应返回。返回的读数据会填充到输出参数(如
mtestRData)中。
方法三:通过API手动设置命令与数据(精确控制)
三、 设置并发事务处理能力
AXI VIP对同时能处理的读写事务数量有默认限制(通常为25)。如果您的测试需要更多并发事务,可以按以下方式提高限额(例如设为40):
对于AXI从设备VIP:
<your_slv_agent>.slv_wr_driver.seq_item_port.set_max_item_cnt(40); // 写事务 <your_slv_agent>.slv_rd_driver.seq_item_port.set_max_item_cnt(40); // 读事务对于AXI主设备VIP:
<your_mst_agent>.mst_wr_driver.seq_item_port.set_max_item_cnt(40); // 写事务 <your_mst_agent>.mst_rd_driver.seq_item_port.set_max_item_cnt(40); // 读事务对于直通VIP:需根据其运行时模式(主模式或从模式),选择上述对应的主或从代理设置方法。