| ||
Systemverilog Direct Programming Interface (DPI)接口的使用越来越广泛,在硬件和软件跨边界通信的场景应用中扮演者重要的角色。就我们上一章《跨平台移植复用篇》中谈到的,DPI可以运用在下面这些地方:
virtual prototyping与simulation的混合仿真
virtual prototyping与FPGA prototyping的混合仿真
simulation与emulation的混合仿真
virtual prototying与emulation的混合仿真
除了simulation之外,其它的验证方式对于读者或者会感到陌生,或者由于实验条件的限制无法更方便地接触到DPI的应用。因此,我们本节谈DPI的应用将就着更简单直观的实际场景,来谈一谈如何满足那些习惯于写C测试的“老测试员”们,使得他们可以在C环境下写C测试用例,而无需关注与底层验证环境是否由UVM实现还是实际硬件去执行C的代码。
本节将会定义间于UVM sequence和C之间的转换层,通过这种方式来降低UVM的使用复杂度,使得测试环境对其它非UVM的verifier更加友好,容易上手。同时,在不少的情况下,测试的随机化并不是最重要的,而将同一个测试用例在不同的测试层次中移植复用反而更加重要。我们这里并不是否定随机测试的重要性,而是尝试将随机测试和直接测试分开,将有可能由C来替代的测试部分从原有的UVM测试中剥离出来,同时在支持C测试的UVM环境中完成迁移。这么做的好处明显,不但降低了verifer们的学习难度,同时也为将来测试代码的复用打下了基础。
在子系统测试中的一个常见的场景如下,由于分布的子系统有时候自身没有处理器单元,或者即便有处理器也仍然预留给外部的处理器接口以供访问。因此,在构建子系统测试平台时,往往需要考虑如何实现子系统外部的master端(即处理器访问行为)来模拟芯片系统级别上的外部访问。一种可供选择的是,挂载一个小而轻便的硬件处理器子系统。该子系统具备了下面的这些特性:
可供参数化的多核以便支持多核运算执行。
具备本地化的存储单元方便更快速的执行编译后的测试代码。
拥有中断处理响应单元,支持中断处理。
支持复位(reset)
支持上电和掉电(power)
尽管有一个小而轻便的硬件处理器子系统,一个真实的硬件子系统用来模拟系统级的外部访问是个不错的主意,但也有着一些限制和不便:
处理器子系统即便“轻便”,但硬件的体积比起软件而言,还是过大。
针对不同子系统可能预留的不同接口(AHB/AXI/OCP),处理器子系统也需要作出相应的接口调整。
testbench的开发者此外还需要将C代码编译、转换二进制文件以及二进制文件下载到memory中的流程集成到原有的测试环境中去。
此外,子系统的接口连接较为复杂,testbench开发者也需要额外的时间理清各个信号的功能。
所以在这种情况下使用一个真实的处理器子系统并不是最好的选择。另外一个可供选择的方案是,直接将已有的总线UVC,例如本案中需要的AHB UVC集成到环境中去,而用户在做访问时需要构建UVM测试用例,同时需要考虑完成在子系统一级的UVM与C的混合测试方案。UVM在这里用来发起外部的访问,而C则由子系统内部的处理器执行,而UVM与C之间的同步可以通过物理方式实现,例如寄存器的同步或者memory内容的同步。这种可能带来的混合方式,尽管增加了一些成本,例如verifier学习UVM测试方法、学习完成UVM与C之间的同步,还有很重要的一点,今后在系统级测试阶段时,无法将子系统级的UVM测试用例直接复用,这带来了额外的成本;但也随之带来了一些好处,例如测试环境更加轻量化、外部接口易于调试、随机化的方式更有助于功能覆盖率的收敛等。
那么有没有可能将C和UVM的便捷都吸收进来,既能保证C在子系统到系统级的复用,又能带来轻量化的测试环境、便于调试、且能模拟处理器的一般行为呢?我们给出一个借助于DPI实现的虚拟处理器方案,来通过SV的主要特性,模拟上述的处理器的主要特性:
支持各种总线接口的读写
支持中断响应
支持时间等待
支持多核并行处理
支持系统复位
接下来我们就上述的主要特性来依靠DPI和UVC来实现它们。
总线接口的读写实现
在实现一个虚拟处理器之前,我们先需要为它定制一个外壳。为什么?因为这样一个外壳在使用起来更像一个真实的处理器,只不过是使用的人不知道它内部的机制罢了。另外一方面,一个合身的外壳,也可能用来替代真实的处理器位置,这样的话,以前使用的“真核”(real core)便更容易被一个“虚核”(virtual core)替代。试想一下,我们给量身定制一个同真核一模一样的边界信号,而该外壳又能模拟真核做出譬如访问寄存器、处理中断的行为等等,那么真核与虚核之间的界限便不再那么明显了,而更真实的模拟在于,用户写的C测试代码,可以原封不动地在真核或者虚核上面自由切换的时候,虚核的“演技”就值得给予最佳演员奖了。
来看一看,一个好演员,需要具备哪些演技呢?
理清处理器子系统的核心时钟和复位信号。一般而言,处理器子系统的时钟和复位信号较多,但我们需要从中找到处理器的核心时钟和复位信号。对于其它时钟和复位信号,我们可以忽略。那么当处理器没有时钟时,虚核应当如何模拟?当处理器被复位时,虚核又应当如何模拟呢?
分清楚总线信号的类型和数量。一般而言,处理器子系统边界上会采用高速总线,例如AXI、OCP等,这里我们为了简单起见,以AHB总线为例。同时也需要考虑清楚如果超过了一组总线,那么在多组总线的情况下,例如AHB0和AHB1作为master端,它们的作用分别是什么?AHB0用来访问memory做指令读取,AHB1用来访问其他从端寄存器?又或者AHB0和AHB1的访问权限和地址访问各不同?在上面的例子中我们只给了一组AHB总线。
考虑清楚,如果是多核访问时,那么针对公共的总线,例如上面的一组AHB总线,多核访问时对于一个AHB UVC的请求和仲裁处理如何实现。这样来模拟真实的多核并行处理C程序。
对于中断的处理时,需要考虑一般处理中断时处理器的行为,即何时进入中断、何时退出中断、何时再恢复到原始中断处的等。
当大致考虑清楚了上面列举出来的一些问题后,可以说,这就为一个演员的良好自我修养打下了基础。那么就第一个话题,如果要做总线接口读写操作时,如何来实现,需要准备一些什么呢?
首先我们需要一个合适的外壳和接口,这里我们省略了一些会影响读者理解DPI使用方式的代码,这里我们将核心的代码整出来,其它的代码我们做注释和省略。
从上面的代码package virtual_core_pkg中可以看到,在假定AHB UVC是可复用的VIP前提下,virtual core的代码分为了三个主要的部分:
virtual_core类的定义,用来实现模拟处理器的行为
建立C和SV之间的DPI链接,同时引出一个virtual_core的句柄virtual_core_pkg::core
DPI方法的实现