🎊 一个简单的UVM项目的学习记录(六)——VCS+Verdi

一个简单的UVM项目的学习记录(六)——VCS+Verdi

从这里开始,将转战到Linux环境下进行仿真。原因在于我用Questa Sim在处理和DPI-C有关的问题上总是不顺利,很难找到解决方案。想到反正也要转到Linux上的,不如现在转了。

一、环境的准备

在Linux中,使用VCS和Verdi进行联合仿真。环境的搭建不妨看我的这篇博客:记一次在Ubuntu18虚拟机上安装VCS等

环境搭建好后,将之前的代码都搬移过来。

二、修改文件结构

之前的文件结构其实并不合理,在使用方面存在不便,因此在改变了环境后,正好顺便也把文件结构顺便改了。更改后的文件目录如下:

agent

C_model

rtl

amplifier

sim

uvm_tb

env

sequence

tb

test

agent主要用于存放agent及其内部组件有关的代码,包括:amp_agent.sv、amp_agent_config.sv、amp_driver.sv、amp_interface.sv、amp_monitor.sv、amp_seq_item.sv、amp_sequencer.sv。

C_model用于存放和C有关的代码,这里暂时先用不到。

rtl用于存放设计代码,由于该项目的设计代码非常简单,因此只有一个子文件夹amplifier,里面有amplifier.v和param_def.v。

sim用于存放脚本文件,之后会用到。

uvm_tb用于和验证环境有关的其他代码。将agent的部分独立出去其实也能一窥其重要性。其子文件夹中:

env含有amp_env.sv、amp_env_refm.sv、amp_env_scb.sv;

sequence含有amp_seq_idle.sv、amp_seq_set_scaler.sv、amp_seq_set_base_number.sv、amp_case1_seq.sv;

tb含有amp_tb.sv和basic_tb;

test含有amp_base_test.sv和amp_testcase1.sv

三、添加package

在Windows中,tb文件是通过amp_pkg.svh对每个文件进行include实现索引的。这种方式非常不便于管理。更加正规的方式是使用package实现打包功能。agent文件夹下创建一个名为amp_agent_pkg.sv的文件,其内部代码如下:

点击查看代码

`ifndef AMP_AGENT_PKG_SV

`define AMP_AGENT_PKG_SV

package amp_agent_pkg;

import uvm_pkg::*;

`include "uvm_macros.svh"

`include "amp_seq_item.sv"

`include "amp_sequencer.sv"

`include "amp_driver.sv"

`include "amp_monitor.sv"

`include "amp_agent_config.sv"

`include "amp_agent.sv"

endpackage : amp_agent_pkg

`endif // AMP_AGENT_PKG_SV

可以看到,package中也主要以导入文件为主。但由于仅导入当前文件夹下的文件,因此管理上更加方便。注意到interface并未包含在其中,这是因为interface在之后会作为单独的文件进行导入。

env中的package为amp_env_pkg.sv,由于需要用到agent中的内容,因此导入agent的包。

点击查看代码

`ifndef AMP_ENV_PKG_SV

`define AMP_ENV_PKG_SV

package amp_env_pkg;

import uvm_pkg::*;

`include "uvm_macros.svh"

import amp_agent_pkg::*;

`include "amp_env_refm.sv"

`include "amp_env_scb.sv"

`include "amp_env.sv"

endpackage : amp_env_pkg

`endif // AMP_ENV_PKG_SV

sequence中的package为amp_seq_pkg.sv,内容如下:

点击查看代码

`ifndef AMP_SEQ_PKG_SV

`define AMP_SEQ_PKG_SV

package amp_seq_pkg;

import uvm_pkg::*;

`include "uvm_macros.svh"

import amp_agent_pkg::*;

`include "amp_seq_set_scaler.sv"

`include "amp_seq_set_base_number.sv"

`include "amp_seq_idle.sv"

`include "amp_case1_seq.sv"

endpackage : amp_seq_pkg

`endif // AMP_SEQ_PKG_SV

test文件下的package为amp_test_pkg.sv,内容如下:

点击查看代码

`ifndef AMP_TEST_PKG_SV

`define AMP_TEST_PKG_SV

package amp_test_pkg;

import uvm_pkg::*;

`include "uvm_macros.svh"

import amp_agent_pkg::*;

import amp_env_pkg::*;

import amp_seq_pkg::*;

`include "amp_base_test.sv"

`include "amp_testcase1.sv"

endpackage : amp_test_pkg

`endif // AMP_TEST_PKG_SV

至此,所有的package编写完成。

四、编写Makefile

4.1 简单的编写

在之前的Questa Sim中,我们使用do文件大幅简化了仿真过程。在这里,也可以使用脚本文件来简化仿真过程。这个脚本就是大名鼎鼎的makefile。

makefile的原理和语法这里不做过多介绍。创建一个名为Makefile的文件,并在其中写入如下代码:

点击查看代码

export FSDB_NAME=amp

SEED=1

VERB=UVM_LOW

TEST_NAME=amp_testcase1

all: comp sim

comp:

vcs -sverilog -full64 +v2k -debug_all -timescale=1ns/1ps -ntb_opts uvm-1.1 -f filelist.f -l comp.log

sim:

./simv +ntb_random_seed=${SEED} +UVM_VERBOSITY=${VERB} +UVM_TESTNAME=${TEST_NAME} \

-ucli -i dump_fsdb_vcs.tcl \

+fsdb+autoflush \

-l sim.log

verdi:

verdi -ssf amp.fsdb -f filelist.f &

clean:

rm -rf *.log *.vdb *simv* *.h *.key *.fsdb *.conf *.rc

rm -rf cg_report csrc vdCovLog verdiLog

这里简要说明一下该makefile脚本:

FSDB_NAME:该变量供外部tcl脚本使用

filelist.f:文件列表,包含有所有要编译的文件

dump_fsdb_vcs.tcl:tcl脚本,用来保存仿真波形

各个选项的意义都可以百度查到。事实上,VCS和Verdi等的资料比Questa Sim多多了,这也是我决定将环境迁移过来的原因之一。

4.2 filelist.f

回到makefile脚本上来。整个脚本中,最关键的地方在于这个filelist.f,其中包含了所有的package和相对路径。+incdir+能够告知VCS,当其需要文件查找时,到哪个文件夹下查询。

点击查看代码

../rtl/amplifier/amplifier.v

+incdir+../rtl/amplifier

../agent/amp_interface.sv

../agent/amp_agent_pkg.sv

+incdir+../agent

../uvm_tb/sequence/amp_seq_pkg.sv

+incdir+../uvm_tb/sequence

../uvm_tb/env/amp_env_pkg.sv

+incdir+../uvm_tb/env

../uvm_tb/test/amp_test_pkg.sv

+incdir+../uvm_tb/test

../uvm_tb/tb/amp_tb.sv

可以看到,使用package加filelist.f的方式,使得整个项目文件更加容易管理,减少了出错的可能。

这里提一下dump_fsdb_vcs.tcl,该tcl文件用于控制保存波形的相关操作,其内容比较简单:

点击查看代码

global env

fsdbDumpfile "$env(FSDB_NAME).fsdb"

fsdbDumpvars 0 "amp_tb"

run

exit

这个FSDB_NAME就是在Makefile中导出的变量,其和.fsdb字段共同组成了一个名为amp.fsdb的文件,该文件保存有仿真后得到的波形信息。

4.3 使用Makefile

在进行仿真之前,需要先对amp_tb.sv进行简单的修改。

点击查看代码

module amp_tb;

import uvm_pkg::*;

`include "uvm_macros.svh"

import amp_test_pkg::*;

logic clk, rst_n;

amp_interface itf(.clk_i(clk), .rstn_i(rst_n));

amplifier dut(

.clk_i (clk) ,

.rstn_i (rst_n) ,

.wr_en_i (itf.wr_en_i) ,

.set_scaler_i (itf.set_scaler_i) ,

.wr_data_i (itf.wr_data_i) ,

.rd_val_o (itf.rd_val_o) ,

.rd_data_o (itf.rd_data_o) ,

.scaler_o (itf.scaler_o)

);

initial begin

clk = 0;

rst_n = 0;

repeat(10) begin

#1ns clk = ~clk;

end

rst_n = 1;

forever begin

#1ns clk = ~clk;

end

end

initial begin

uvm_config_db #(virtual amp_interface)::set(null, "uvm_test_top.env.i_agt", "vif", itf);

uvm_config_db #(virtual amp_interface)::set(null, "uvm_test_top.env.o_agt", "vif", itf);

end

initial begin

run_test();

end

endmodule : amp_tb

比较重要的修改就是去掉了修改冗余度的语句,并且run_test()中没有给任何参数,因为这些参数都可以在Makefile中进行设置。

以上过程都完成之后,就能着手仿真了。

在主界面输入命令make all,之后将以UVM_LOW的冗余度编译运行amp_testcase1这一测试用例。运行完成后,当前路径下出现两个分别命名为comp.log和sim.log的文件。使用vim comp.log打开comp.log,可以看到详细的编译情况;而使用vim sim.log打开sim.log,则可以看到详细的仿真情况。可以看出,其仿真情况与Questa Sim中的日志相同。

使用makefile的另一个好处在于:只需通过改变上述变量的内容,就能灵活地进行仿真。将VERB的值改为UVM_FULL、将TEST_NAME的值改为amp_base_test,之后再次执行命令make sim,会发现此时执行的测试用例变成了amp_base_test,可以再次打开sim.log文件,发现其内容已经发生了完全的改变。当然,并没有因为更改了测试用例就需要重新编译,这对于大型项目的测试简直是福音。

五、使用DPI-C

在Ubuntu+VCS的环境下,使用DPI-C非常方便。首先是在C_model文件夹下创建两个文件:c_amplifier.c和cpp_amplifier.cpp,两个文件的内容分别如下:

c_amplifier.c:

点击查看代码

#include

int amplifier(int base_number, int scaler) {

return amplifier_by_cpp(base_number,scaler);

}

cpp_amplifier.cpp:

点击查看代码

#include

#ifdef __cplusplus

extern "C" {

#endif

class c_cpp{

public:

c_cpp(){};

~c_cpp(){};

int calculate(int base_number, int scaler);

};

int amplifier_by_cpp(int base_number, int scaler);

#ifdef __cplusplus

}

#endif

int c_cpp::calculate(int base_number, int scaler){

using namespace std;

cout<<"calculated by cpp"<

return base_number*scaler;

};

int amplifier_by_cpp(int base_number, int scaler){

c_cpp c_inst;

return c_inst.calculate(base_number,scaler);

};

然后在filelist.f中加入两个文件:

点击查看代码

../C_model/c_amplifier.c

../C_model/cpp_amplifier.cpp

之后修改amp_env_refm.sv,主要是加入DPI-C接口,并在main_phase()中使用该接口。

点击查看代码

`ifndef AMP_ENV_REFM_SV

`define AMP_ENV_REFM_SV

import "DPI-C" context function int amplifier(input int base_number, int scaler);

class amp_env_refm extends uvm_component;

`uvm_component_utils(amp_env_refm)

uvm_blocking_get_port #(amp_seq_item) gp;

uvm_analysis_port #(amp_seq_item) ap;

amp_seq_item t;

amp_seq_item scb_t;

int res;

extern function new(string name = "amp_env_refm", uvm_component parent = null);

extern function void build_phase(uvm_phase phase);

extern task main_phase(uvm_phase phase);

endclass : amp_env_refm

function amp_env_refm::new(string name = "amp_env_refm", uvm_component parent = null);

super.new(name, parent);

`uvm_info(get_type_name(), "created", UVM_LOW)

endfunction : new

function void amp_env_refm::build_phase(uvm_phase phase);

super.build_phase(phase);

gp = new("gp", this);

ap = new("ap", this);

endfunction : build_phase

task amp_env_refm::main_phase(uvm_phase phase);

super.main_phase(phase);

while(1) begin

t = new("t");

scb_t = new("scb_t");

gp.get(t);

scb_t.copy(t);

res = amplifier(t.base_number, t.rd_scaler); // use DPI-C

scb_t.rd_data = res;

ap.write(scb_t);

end

endtask : main_phase

`endif // AMP_ENV_REFM_SV

最后,重新编译并仿真,可以从输出结果中看到确实调用了cpp文件。

至此,整个项目完成。

🎈 相关推荐

正在阅读:如何彻底删除猎豹浏览器 猎豹浏览器彻底删除方法教学【详解】如何彻底删除猎豹浏览器 猎豹浏览器彻底删除方法教学【详解】
笔记本深度放电好不好 彻底放电保养电脑【详解】
泰拉瑞亚猩红矿怎么挖不动 猩红矿挖矿攻略
🏷️ 365dni是什么

泰拉瑞亚猩红矿怎么挖不动 猩红矿挖矿攻略

📅 06-27 👀 3325
模拟人生到伴侣怎么买玫瑰
🏷️ 中爱365APP

模拟人生到伴侣怎么买玫瑰

📅 08-20 👀 1569
延长动静脉内瘘使用时间,这些维护要点千万要掌握!
模拟人生到伴侣怎么买玫瑰
🏷️ 中爱365APP

模拟人生到伴侣怎么买玫瑰

📅 08-20 👀 1569