本文授权转发自知乎用户 ljgibbs 链接:https://www.zhihu.com/people/ljgibbs
本系列我想深入探寻 AXI4 总线。不过事情总是这样,不能我说想深入就深入。当前我对 AXI总线的理解尚谈不上深入。但我希望通过一系列文章,让读者能和我一起深入探寻 AXI4。
欢迎来到深入 AXI4 总线的实战篇,系列第二篇文章中,我们将首先了解调用 AXI VIP 产生激励与响应的方法,并完成一个小目标:实现三种情况下的握手信号。
本文的实战在第一篇的示例工程上,新建 tb 来实现我们的功能。新建 tb 中的逻辑由 demo tb 的内容搬运简化而来。
本来计划新建一个工程,但是阅读 PG267 (IP 核的产品文档)发现,当前 Vivado 对于该 IP 的支持还比较弱,需要将 IP 的实例名以及层次路径硬编码至 tb 中,如果新建工程还比较麻烦。所以本文暂时还是在 example 的基础上展开 。
想要重新搭建工程的读者请注意阅读 demo tb 开头的说明,或者 PG267 第六章中的内容。
本文的场景为主机与从机之间通过 Pass-through (以后叫 ta 中间机?)进行通信。从机选用 mem 模式,有自己的存储模型,即使用 mem_stimulus.sv 作为激励。关于存储模型,我们将在后续的文章中讨论。
我们的改动在于主机的激励部分,以原先的 mst_stimulus.sv 为基础,构建我们自己的主机激励,改动后的 testbench 结构如下图所示。
是的,新的激励加上了 headbig 字段,这来自于 深入 AXI4 总线 系列文章的英文名:Headbig AXI4。
PG 文档中,Xilinx 表示 VIP 基于 SystemVerilog 语言开发,同时在 API 的设计上,命名与数据结构的设计均参考了 UVM 框架,便于 VIP 在验证系统中的集成。由于本文的重点不在于 UVM 或者 API 的设计,因此仅跟着 demo 以及 PG 中的 API 调用流程过一遍。
主机 master
首先来看主机,定义于 axi_vip_master_mst_stimulus.sv
中
agent = new("master vip agent",DUT.ex_design.axi_vip_mst.inst.IF);
agent.start_master();
fork
begin
//调用写传输事务 API
end
begin
//调用读传输事务 API
end
join
multiple_write_transaction_full_rand ("single write",1);
single_write_transaction_api("single write with api",
.id(mtestWID),
.addr(mtestWADDR),
.len(mtestWBurstLength),
.size(mtestWDataSize),
.burst(mtestWBurstType),
.wuser(mtestWUSER),
.awuser(mtestAWUSER),
.data(mtestWData)
);
我们常说,不想知道 API 函数之下发生了什么的程序员不是好程序员,IC 工程师同样如是。以较简单的定制化写传输事务函数为例,所谓函数实质上是一个 sv task,以下是 task 中的主要内容:
axi_transaction wr_trans;
wr_trans = agent.wr_driver.create_transaction(name);
wr_trans.set_write_cmd(addr,burst,id,len,size);
wr_trans.set_prot(prot);
//...
wr_trans.set_data_block(data);
agent.wr_driver.send(wr_trans);
首先声明一个 axi 传输事务对象,然后在主机 ip 的 agent 下建立传输事务。
通过 API 函数设定写命令信息,设定传输属性以及待传输的数据块。数据块的数据类型为
bit [4 * 1024 * 8 - 1:0]
从机 slave
接下来,我们看一下从机的相关流程,定义于 axi_vip_master_mem_stimulus.sv
中。
同样为从机创建并启动相应 agent,此处与主机相似不表。
在 demo 中构造了一个虚拟数据作为后续对主机读数据的回应,因为本文的主要工作是得到握手信息的波形,因此并不会实际存储主机写入的数据,而是在主机读取任意地址时,返回这个虚拟数据。
最后,从机调用 API 产生 wready 信号应答
task user_gen_wready();
axi_ready_gen wready_gen;
wready_gen = agent.wr_driver.create_ready("wready");
wready_gen.set_ready_policy(XIL_AXI_READY_GEN_OSC);
wready_gen.set_low_time(1);
wready_gen.set_high_time(2);
agent.wr_driver.send_wready(wready_gen);
endtask
此处表示 wready 信号在从机空闲时周期性生成,有效时间为 2/3,我们可以在后续的波形中看到。
我们对主机的激励代码进行修改,仅保留单次定制化的读写传输事务,地址为 0x0,突发长度为 0。在波形中我们得到了三种情况下的握手信号。
(1)VALID 信号等待 READY 信号
在 tb 中主机并行地启动读写传输事务,AR/W VALID 同时置高,在等待从机给出 READY 信号后完成地址与控制信号的传输,此时地址为 0x0.
(2)READY 信号等待 VALID 信号
主机在发出读传输事务后,置高 RREADY 信号等待接收从机返回的读数据。在从机置高 RVALID 后,读传输事务完成。
(3)READY 与 VALID 信号同时置起
在设置从机的 READY 信号类型时,我们设置为周期性置高 READY,从下图中可以看到,READY 信号在送出 2 个周期高电平后置低 1 个周期。
在这个场景中,写数据通道中的 WREADY 信号正好与 WVALID 信号同时置起,解锁了最后三种握手姿势中的最后一种,OK 本文实战篇收工了。
本文首先介绍了 AXI VIP 中产生传输事务的基本方法。基于 demo 修改了一个简单纯粹的例子,并基于这个例子观察到了握手信号。