| ||
virtual_core类的定义
上面的virtual_core中实现了下面几个方法:
extern task writew(int unsigned addr, int unsigned data);
extern task readw(int unsigned addr, output int unsigned data);
extern task delay(input int t);
extern task print(input string message);
writew和readw方法即是将接收到的参数利用AHB UVC转化为总线的访问,这中间存在着一些从TLM到物理接口的转化。为了简单起见,我们并没有深入AHB UVC的实现、sequence的使用等,而是重点突出了virtual_core类该有的一些方法结构。delay方法即是为了解决上述提到了为了解决时间等待的问题,这里要注意的是,为了模拟同硬件处理器真实等待的时间,在virtual_core::delay方法中等待的单位周期数需要伴随着不同的项目进行调整,而这么做也是为了保证仿真的时间大致相同。而在硬件仿真中,考虑到编译后的C无法在仿真中实现print函数,我们将该函数特意导出到C一侧,这样利用DPI和虚拟核,就可以提供简单的调试打印方法。
DPI方法的实现
在定义了virtual_core之后,我们还需要将日后例化的虚拟核对象和DPI方法一同输出。这里的建议是,读者在尝试使用DPI方法定义和输出时,将它们都实现在package中。一旦实现之后,将来在C一侧便可以调用这些方法,而这些方法依靠虚拟核句柄,便能够进行该有的操作。下面便是主要的几个面向C输出的SV方法:
没有什么意外的话,这些方法只是进一步地在package中重复定义了属于virtual_core的方法,而利用virtual_core句柄来间接调用方法。接下来,将virtual_core_pkg编译之后,仿真编译器便会同时生成一些与DPI SV方法对应的C函数头文件。这些头文件与上述的SV DPI方法相关的定义如下:
于是SV便可以利用这些函数来实现与SV之间的DPI程序,下面给出一段C例码:
那么C代码一侧和SV一侧,谁先触发谁呢?还是他们一开始并行运行呢?实际上,在C与SV联合仿真时,是由SV来调用C的,毕竟simulator还是SV的主场嘛。那么,SV在哪儿来触发C呢?
便是这句话,在virtual_core::run_phase(UVM component phase自动执行)中,通过模拟等待复位信号,继而像真核一样来执行C代码,这便是由SV触发C的“播放键”。那么就接着这一段代码,C跟SV之间缠绵悱恻的关系,我们通过下面这张时序图做进一步的理解:
可以看到的是,首先由SV触发了C一侧,接下来C和SV便并行开始运行了。这里的C代码执行,并不像硬件执行时需要从存储中读取指令再解析执行,也不需要从对处理器系统进行初始化配置,而直接可以进入正题,执行主程序。而C与SV之间的“同步点”便是由C导入SV或者由SV导入C的方法。这样借助这些DPI方法,C与SV之间就能够很好的交谈了。从上面的简单例码中,读者可以了解到,如何实现一份较为原始的虚核的行为。我们简单实现了虚核的这些特性:
总线访问
时间等待
调试打印
谢谢你对路科验证的关注,也欢迎你分享和转发真正的技术价值,你的支持是我们保持前行的动力。