在实际验证过程中,仿真效率是我们常常面临的挑战之一。尤其是在修改代码时,明明只改动了一个文件(例如,在testcase中增加了一行打印),但编译却需要重新编译整个工程中的所有文件。这种情况不仅浪费了大量时间,还显著降低了仿真效率。为了应对这种问题,常用的解决方法有两种:充分利用UVM的runtime cmdline传递参数机制和增量编译。然而,即使采用了增量编译,仿真效率仍然受到一定影响,因为仿真器无法准确识别哪些文件已经被修改。那么,是否有其他方法可以进一步提高仿真效率呢?答案是:[分块编译(Partition Compile)]。本文将详细介绍这两种方法及其优缺点,特别是分块编译如何作为增量编译的一种有效补充。
1. 充分利用UVM的runtime cmdline传递参数机制
在UVM中,我们可以通过命令行动态地传递参数,而不必重新编译代码。这对于提高仿真效率非常重要,因为每次修改UVM相关参数时,都可以避免重新编译整个项目。
比如,在测试过程中,我们可以使用命令行来动态修改UVM的相关参数,如UVM_TESTNAME
、UVM_VERBOSITY
等,这样就能在运行时直接影响UVM环境的行为,而不需要重新编译源代码。具体来说,只需在仿真启动时通过命令行传递这些参数,例如:
1 | vcs +UVM_TESTNAME=test1 +UVM_VERBOSITY=UVM_LOW |
这种方式不仅避免了不必要的重新编译,还能更灵活地调整仿真设置,提高工作效率。
2. 增量编译
增量编译是提升仿真效率的另一种常用方法。它的理想情况是:只有修改过的文件需要重新编译,而未修改的文件则跳过编译。通过这种方式,我们可以显著减少编译时间。
在VCS中,增量编译可以通过添加-Mupdate
参数来启用。该参数允许仿真器检测文件是否发生了修改,只有修改过的文件才会被重新编译。然而,实际使用中,我们发现即使启用了增量编译,仿真器依然会重新编译一些未修改的文件。这是因为仿真器的优化能力还不够,无法准确识别哪些文件被修改了。
3. VCS分块编译(Partition Compile)
为了进一步提高仿真效率,VCS提供了一种名为分块编译(Partition Compile)的方法。分块编译的核心思想是将整个工程中的文件划分为多个独立的“块”,只有当某个块中的文件被修改时,才会重新编译该块中的文件。通过这种方式,我们可以减少每次编译所需处理的文件数量,从而提高仿真效率。
分块编译的基本原理
分块编译的本质是将代码拆分成若干个独立的块,每个块都包含一组相关的文件。只有当某个块中的文件发生变化时,仿真器才会重新编译该块。而在其他块中没有修改的文件则不会被重新编译。因此,通过合理划分这些块,我们可以减少编译的范围,从而提高效率。
然而,分块编译的精细程度需要在“精细”和“高效”之间找到一个平衡。如果将文件拆分得过细,仿真器需要处理的块会增多,从而消耗更多的系统时间;如果块划分过粗,又可能导致重新编译的文件过多。因此,在块分割的粒度上,需要根据实际情况进行调节。
VCS分块编译的实现
在VCS中,我们可以通过添加-partcomp
参数来启用分块编译功能。具体的命令如下:
1 | vcs -partcomp |
此外,VCS还支持自动划分Partition的大小和数量,可以通过以下选项来指定:
1 | vcs -partcomp=autopart_[low|medium|high] |
这三个选项分别对应不同的分块粒度(低、中、高),一般情况下可以使用默认设置,不必手动调整。
- 添加
-pcmakeprof
把编译过程中的每一步所花费的时间做分析打印,并在编译日志的结尾进行输出,这样方便比较不同编译参数所花费的编译时间的区别。
1 | vcs -pcmakeprof |
纵向分析:VCS仿真流程
阶段 | 描述 | 作用/功能 |
---|---|---|
Parsing | 解析过程,读取文件并进行语法分析。 | 将Verilog/SystemVerilog源代码转换为仿真器可以理解的格式,检查语法和结构的正确性。 |
_Elabcom | 编译文件生成过程,生成提供给Verdi解析的编译文件(需要-kdb 选项)。 |
生成仿真器调试信息,供Verdi等工具解析和调试。 |
Compiling | 编译过程,检查语法错误并生成中间二进制文件。 | 检查Verilog/SystemVerilog代码中的语法错误,并生成Elaboration阶段可以识别的二进制文件。 |
Elaboration | 精化过程,计算模块的参数值,处理模块的绑定关系,生成最终可执行文件simv 。 |
根据设计层次结构计算参数,处理模块绑定关系,生成最终的可执行仿真文件simv 。 |
横向分析:VCS仿真性能指标
性能指标 | 描述 | 说明 |
---|---|---|
Real time | 程序从开始到结束的总时间。 | 仿真程序执行的真实时间,包括所有计算、I/O操作等。 |
User time | 程序在用户模式下的CPU耗时。 | 仿真程序在执行用户代码时消耗的CPU时间。通常与程序逻辑的复杂度相关。 |
Sys time | 程序在内核模式下的CPU耗时。 | 仿真程序在执行系统调用、I/O操作等内核级任务时消耗的CPU时间。 |
Virt | 程序的虚拟内存空间大小。 | 仿真程序的虚拟内存空间大小,包括所有可访问的内存地址空间。 |
Res | 程序已映射到物理内存的部分。 | 程序在物理内存中占用的实际空间。 |
Shr | 程序占用的共享内存大小。 | 仿真程序占用的共享内存区域,多个进程可能会访问这些内存。 |
手动指定Partition
如果需要更精细的控制,我们还可以手动指定Partition。通过在VCS编译命令中指定-top topcfg
选项,可以指定特定的配置文件,并在该配置文件中定义Partition。示例如下:
1 | vcs -partcomp -top topcfg topcfg.v |
-top
后面跟的topcfg根据我的实测是topcfg中的config_name
在topcfg.v
文件中,我们可以定义具体的Partition,示例如下:
1 | config topcfg; |
在这个例子中,我们将apb_tb
、uvm_pkg
、svt_amba_uvm_pkg
、svt_uvm_pkg
和apb_pkg
分别定义为独立的Partition,当其中的文件发生变化时,仿真器只会重新编译相应的Partition。(其中apb_tb是我顶层的tb, instance是例化的dut, cell是module_name)
Partition并行参数
-fastpartcomp=j4
中的j4
表示使用 4 个并行作业来执行编译任务。并行处理的优势在于,它可以同时处理多个部分,大大提高编译效率(j和4之间没有空白字符)。
1 | -fastpartcomp=j4 |
避免在$unit空间导入package:增量编译效率的陷阱
在进行Verilog/SystemVerilog的设计和验证时,增量编译是一项至关重要的技术,它能够有效减少编译时间,提高仿真效率。然而,在实际使用过程中,我们需要注意一些常见的陷阱,特别是在项目的$unit空间中导入package(包)这一做法。
什么是$unit空间?
在Verilog/SystemVerilog中,$unit
空间指的是顶层全局空间,通常是package...endpackage
、module...endmodule
、interface...endinterface
之外的部分。简单来说,$unit层次是指那些不属于具体模块、接口或包的地方。它包括了定义文件级别的各种设置或行为的区域。
为什么避免在$unit空间导入package?
导入package
的本意是为了共享其中的定义、类型、函数等,避免重复编写相同的代码。但如果我们在$unit空间导入package
,会带来以下几个问题:
- 增量编译失效: 当我们在$unit空间导入一个
package
时,这个package
的变动将直接影响到所有使用它的模块和文件。假设这个package
被多次导入,那么在后续修改package
中的内容时,仿真器无法精确识别哪些文件发生了变化,进而会导致整个项目的重新编译。这使得增量编译失效,浪费大量编译时间。 - 影响编译效率: 增量编译的核心优势是仅编译修改过的部分文件,但如果我们在$unit空间导入
package
,会使得修改package
文件后,所有依赖它的模块都会被重新编译。对于大型项目来说,这种情况会显著降低编译效率,特别是当package
较为庞大或被多个模块依赖时,编译时间会显著增加。 - 影响项目的可维护性: 在$unit空间中随意导入
package
,可能导致代码结构混乱,依赖关系复杂,难以追溯具体依赖了哪些文件,增加了调试和维护的难度。
如何避免这个问题?
为了避免在$unit空间导入package
带来的问题,我们可以采取以下策略:
- 局部导入
package
最好将package
的导入限制在具体的模块、接口或包内部。这样只有在需要的地方才会导入,而不会影响到整个项目的编译。 - 合理划分文件结构
尽量将公共包和模块隔离开来,在独立的文件夹中进行管理,避免包的导入影响到顶层全局空间。 - 避免频繁修改核心
package
如果package
中包含了多个常用的定义或函数,尽量减少对其结构的修改。若确实需要修改,尽量使这些修改局部化,避免频繁改动全局影响。
总结
提高仿真效率是每个验证工程师都希望解决的问题,尤其是在大型项目中,避免不必要的全量编译可以显著节省时间。通过UVM的runtime cmdline参数机制,我们可以避免重新编译整个项目,只通过命令行传递参数来修改UVM环境;通过增量编译,我们可以减少不必要的文件编译,但仍会遇到仿真器无法精确识别文件修改的情况;而VCS的分块编译则是一种有效的补充方法,它通过将文件划分为多个独立的块,减少每次需要重新编译的文件数量,从而提高仿真效率。
在实际工作中,我们可以根据项目的需求和仿真器的表现来选择合适的优化方式。分块编译作为增量编译的补充,将会在提高效率和缩短仿真时间方面发挥重要作用。
本文链接: https://talent-tudou.github.io/2024/11/16/IC/提高VCS仿真效率-UVM Runtime Cmdline和VCS分块编译/
版权声明: 本作品采用 CC BY-NC-SA 4.0 进行许可。转载请注明出处!