本文继续之前的章节(新手学习Vivado XDMA (1) - 配置详细分析-CSDN博客)对仿真的工程以及过程进行分析。
项目框架介绍
Design 部分
根据前文打开的example工程的设计部分如下所示:
上图中的右侧3个BRAM代表的是用户侧的逻辑设计,与下图工程中的xdma_app中3个 blk_mem_gen对应。上图中的 DMA Subsystem for PCIe 与下图中的 xdma_0 对应,这个也是我们上一篇文章中配置好的IP,可以看出它还包含了 PCIe IP。CQ/CC/RQ/RC定义如下:
This diagram refers to the Requester Request (RQ)/Requester Completion (RC) interfaces, and the Completer Request (CQ)/Completer Completion (CC) interfaces.
而xilinx_dma_pcie_ep作为design的顶层设计对外的接口也比较简单,
module xilinx_dma_pcie_ep #
(
parameter PL_LINK_CAP_MAX_LINK_WIDTH = 2, // 1- X1; 2 - X2; 4 - X4; 8 - X8
parameter PL_SIM_FAST_LINK_TRAINING = "FALSE", // Simulation Speedup
parameter PL_LINK_CAP_MAX_LINK_SPEED = 2, // 1- GEN1; 2 - GEN2; 4 - GEN3
parameter C_DATA_WIDTH = 64 ,
parameter EXT_PIPE_SIM = "FALSE", // This Parameter has effect on selecting Enable External PIPE Interface in GUI.
parameter C_ROOT_PORT = "FALSE", // PCIe block is in root port mode
parameter C_DEVICE_NUMBER = 0, // Device number for Root Port configurations only
parameter AXIS_CCIX_RX_TDATA_WIDTH = 256,
parameter AXIS_CCIX_TX_TDATA_WIDTH = 256,
parameter AXIS_CCIX_RX_TUSER_WIDTH = 46,
parameter AXIS_CCIX_TX_TUSER_WIDTH = 46
)
(
output [(PL_LINK_CAP_MAX_LINK_WIDTH - 1) : 0] pci_exp_txp,
output [(PL_LINK_CAP_MAX_LINK_WIDTH - 1) : 0] pci_exp_txn,
input [(PL_LINK_CAP_MAX_LINK_WIDTH - 1) : 0] pci_exp_rxp,
input [(PL_LINK_CAP_MAX_LINK_WIDTH - 1) : 0] pci_exp_rxn,
input sys_clk_p,
input sys_clk_n,
input sys_rst_n
);
作为EP,只有2个lanes,即4对差分数据输入,以及1对参考时钟输入,最后是复位管脚。
Simulation 部分
测试框架如下:
其中RP和EP两个参考时钟虽然是独立的两个模块,但在tb里面的参数配置是一致的,所以可以认为是完全同源的时钟(100MHz)。EP则是我们的测试对象(DUT),其内部设计在design 部分已经介绍过。 Simulation 文件夹结构如下:
笔者分析到这里看到整个simulation文件还是比较多的,并且在board.v即top里面并没有发现测试开始的入口,并且由于对PCIe的通信机制不懂,所以决定先启动仿真,等待仿真log出来以后,根据log反向分析整个工作过程。
仿真分析
仿真的启动
由于是新手学习,我们也不用modelsim, questa 或者VCS之类的来仿真了,直接用Vivado 自带的 xsim 来启动,配置如下:
第7步需要改默认仿真时间到 -all ,否则仿真还没完成就暂定下来了。第8步是把design和tb中的所有信号都能存储波形,这样我们后续想要观察某个信号的时候就可以直接从scope->object中找到对应的信号添加,否则事先不在波形窗口中的信号是不记录波形的,这会导致我们每当要新添加(观察)一些信号的时候,都得从头启动仿真,极其费时费力。以下是Tcl console 输出的log最后的信息,用了21分钟。
launch_simulation: Time (s): cpu = 00:01:47 ; elapsed = 00:21:09 . Memory (MB): peak = 1317.504 ; gain = 35.629
仿真log分析
首先我们需要找到log中系统复位结束的时间,这个是所有功能即将开启的起始时刻。
[ 4995000] : System Reset Is De-asserted...
[ 143423604] : Transaction Reset Is De-asserted...
[ 143427504] : Writing Cfg Addr [0x00000001]
[ 143463504] : Reading Cfg Addr [0x00000032]
[ 143491504] : Writing Cfg Addr [0x00000032]
[ 176147529] : Transaction Link Is Up...
[ 176155529] : TSK_PARSE_FRAME on Transmit
发现首先是在 143427504 ps的时候往地址 0x00000001 进行了配置写入。我们可以在整个目录下搜索 “ Writing Cfg Addr ” 看下是谁操作了这一步,发现是pci_exp_usrapp_cfg模块中的task: TSK_WRITE_CFG_DW. 然后通过搜索这个task 名字来确定是谁调用了这个task, 以此类推一层一层,最终发现我们应该从pci_exp_usrapp_tx.v的第314行作为仿真的入口进行分析。
board.RP.tx_usrapp.TSK_SIMULATION_TIMEOUT(10050)
这个是设置仿真超时时间,但搜索整个workspace后发现,并不会起作用,而且 10050 远远早于上述的复位结束时间。
board.RP.tx_usrapp.TSK_SYSTEM_INITIALIZATION
顾名思义,系统初始化过程,整个task的工作是等待传输接口的复位和链路的建立。
PG213:
等待事务传输接口复位以及根端口模型与端点 DUT 之间的链路建立完成。此任务必须在端点核初始化之前调用。
task TSK_SYSTEM_INITIALIZATION;
begin
//--------------------------------------------------------------------------
// Event # 1: Wait for Transaction reset to be de-asserted...
//--------------------------------------------------------------------------
wait (reset == 0);
$display("[%t] : Transaction Reset Is De-asserted...", $realtime);
//--------------------------------------------------------------------------
// Event # 2: Wait for Transaction link to be asserted...
//--------------------------------------------------------------------------
board.RP.cfg_usrapp.TSK_WRITE_CFG_DW(32'h01, 32'h00000007, 4'h1);
board.RP.cfg_usrapp.TSK_READ_CFG_DW(DEV_CTRL_REG_ADDR_RP/4);
board.RP.cfg_usrapp.TSK_WRITE_CFG_DW(DEV_CTRL_REG_ADDR_RP/4,( board.RP.cfg_usrapp.cfg_rd_data | (DEV_CAP_MAX_PAYLOAD_SUPPORTED * 32)) , 4'h1);
if (LINK_CAP_MAX_LINK_SPEED_EP>1) begin
wait(board.RP.pcie3_uscale