解读UVM and C – Perfect Together
文章获取方式:路科验证--->资源--->DVCon2018-USA.zip--->08_3
http://rockeric.com/resource/paper/
文章主要内容:使用DPI-C集成UVM bench和C code时,遇到的最大问题在于:域。DPI-C的域可以是module实例,interface实例或全局根域(the global root scope)。UVM bench没有这种域,它是基于动态类的,而不是基于静态实例的,但C是基于静态的。
文章详细介绍了如何实现从图1=>图2=>图3
The SystemVerilog Interface
Interface是兼有“软硬件”的特性,即interface可以实例化,使用virtual interface可以在UVM bench中使用interface。因此选择interface作为DPI-C的域最为合适。
Interface中定义了SV一侧export到C一侧的方法,sv_hello和sv_start_sequenceC。其中,声明了 sequencer句柄,再使用动态转换,然后调用sequencer内的同名方法。
The UVM Agent
其中,这2行代码很重要。
这样,interface和sequencer之间就建立了联系。第一句,interface中的uvm_sequencer_base类型的sqr被初始化,才能在interface中调用sequencer内的方法。第二句,sequencer中的interface被初始化,可以在sequencer中通过DPI-C调用C一侧的方法。
The UVM Sequencer
任务c_start_thread()是通过DPI-C调用C一侧的方法,使用fork-join并行4个线程。任务sv_start_sequenceC是由C code调用,启动sequence后把结果输出到C一侧。
The UVM Sequence
上图,sequenceA中,通过interface调用C一侧的方法,c_hello和c_datatype_array_of_10_int。
Threaded Code
在sequencer的任务c_start_threads()中,4个线程并行执行,但是每次只执行1个线程。当1个线程启动时,它就得到了控制权,而另一个线程得到控制权的方法是:当前线程将控制权放弃或者“让步”。“让步”的形式表现为执行#delay, wait() , a @(posedge clk)等时间语句。正是因为有这种“让步”行为,才能让4个线程看似并行执行。
C code中的“jj”是一个全局变量,但不是一个安全的变量。4个线程并行执行过程中,“jj”的值会被不同的线程改变,这不是我们所期望的。
左边是“让步”控制权,右边是放弃控制权。
图中,紫红色表示C code一侧启动的sequenceC,紫色和蓝色分别是SV一侧启动的sequenceA,sequenceB。
在同一个sequencer上,挂载了sequenceA,sequenceB,sequenceC,使用并行语句,出现“让步”行为,如波形图所示。
C code在其他场景下使用:
Stimulus Generator:数据由C一侧产生,通过DPI-C送到SV一侧。
Data checker:在C一侧产生预测数据,将监测到的DUT输出送到C一侧进行对比。
Bus transfer generator:C一侧发送总线读写请求。
总结
这篇文章详细描述了将interface作为域,通过DPI-C集成UVM和C的例子。将interface作为域可以 消除集成和连接问题,最重要的是它兼有“软硬件”的特性。
思考:
A. interface前加virtual和不加的区别?
Interface是“硬件”特性,类似于module可以例化;virtual interface是“软件”特性,在UVM bench中是指向例化interface的指针。因此,interface才有“软硬件”的特性。
B. 除了interface外,还有哪些地方可以作为域?
1.Module
Import:将DPI-C的实现放在C的class里,声明并例化C class,封装C指针的调用,在SV一侧的组件(run_phase/main_phase)中直接调用封装后的task/function。
Export:在module中似乎没法调用。
2.Package
将DPI-C的实现(import和export)放在UVM的class里,再把这个class放在package中,在UVM bench里创建这个class,使用句柄调用DPI-C的task/function。
C. 并行线程的本质?
使用fork-join(join_none)执行并行线程,其本质是当前线程在执行#delay, wait() , a @(posedge clk)等时间语句时,将控制权交给其他线程,使得所有线程看似并行执行。
D. 全局变量和局部变量的使用区别?
文中的例子表明,在执行并行线程时,并行线程涉及到的全局变量是不安全的,需要使用局部变量。
E. Sequencer的仲裁
文中的例子表明,多个sequence(有继承关系)挂载到同一个sequencer上,sequencer需要仲裁。仲裁mode默认是SEQ_ARB_FIFO,可以在test层用函数set_arbitration改变仲裁mode。
注:以上思考完全是个人理解,如有错,欢迎留言!
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)