摘要:本文记录CPU验证环境中一些基本但重要的机制,包括验证环境中的编译、CPU启动配置、Tube机制和Testcase结束机制。
1. 前言
本文记录CPU验证环境中一些基本但重要的机制,包括验证环境中的编译、CPU启动配置、Tube机制和Testcase结束机制。
2. 编译
CPU验证环境编译分为软件编译和硬件编译。因为CPU的Core会去memory中取指令去执行,而这些指令需要我们提前生成好,并后门放在memory中取,这些指令的集合通常使用hex格式的文件存储,软件编译就是将C语言或汇编语言转换为二进制指令码,并存储在hex格式文件中。硬件编译是将RTL和UVM验证环境一同编译起来,形成一个验证环境的骨架,软件编译的hex文件依托于硬件编译产生的平台。编译环境如图1所示。
图1 编译环境
2.1 软件编译
软件编译通常使用makefile来管理的。makefile调用各CPU的子makefile去生成各个CPU的hex文件。步骤如图2所示。
图2 软件编译流程
确定软件编译环境(编译器、编译选项、编译文件和目录)
将文件编译成.o格式的文件
确定link方式(link器、link选项、规则、文件)
将.o文件link成elf文件
将elf文件转成hex文件
2.2 硬件编译
硬件编译就是使用Xcelium/Questasim/VCS对SystemVerilog代码进行编译、细分和开启仿真的过程。在如今普遍使用UVM的环境中,会形成一个UVM树,使用uvm_test来启动仿真。
在仿真开始时,验证环境会使用后门加载软件编译的hex文件到对应的DDR/SRAM/ROM里。根据加载到memory类型的不同,通常还有不同的方式:
如果memory是真实RTL,可以使用SystemVerilog语法的$readmemh将hex数据从后门填充到真实DDR/RAM/ROM里。
如果memory是虚拟RAM,通常用虚拟RAM提供的函数将hex数据从后门填充进去。
3. CPU启动配置
3.1 确定PC初始值
CPU启动最关键的要确定PC值,PC值决定了CPU从哪里开始取值并执行。
对于ARM Cortex-A来说,初始PC是放在RVBAR(Reset Vector Base Address Register
)寄存器中,RVBAR寄存器是RO类型的,也就是实现就定义好的了。在IP验证中,通常force这个寄存器的值来控制CPU启动PC值。在SoC验证中,如果RVBAR为0,那么会提前在0地址处放置跳转指令(BL),将Cortex-A CPU的PC跳转到真正的启动地址去执行。
对于ARM Cortex-M来说,没有RVBAR寄存器,在复位后会查询中断向量表并进入reset中断函数执行,因此在reset中断函数里可以控制PC跳转到真正的启动地址。中断向量表一般存放在ROM中,Cortex-M CPU在boot的过程中可以读取它的内容。
3.2 Cortex-A启动流程
Cortex-A启动流程通常按以下步骤进行:
把通用寄存器值、堆栈指针、link指针和状态寄存器全部初始化为0;
关掉Trap功能;
设置VBAR(Vector Base Address Register),使它指向中断向量表;
初始化堆栈指针,内容来自scatter file指定的;
使能NEON和初始化相关寄存器为0;(包括使能其它想要打开的特性)
创建页表,配置TTBR/TCR/MAIR等;
使能cache和MMU;
使能中断;
进入main主程序,完成主要操作;
进入WFI;
通常步骤1~8以及步骤10在CPU验证中是固定的流程,不需要反复写,大部分验证人员只需要在步骤9的main函数中完成想要验证的功能。
3.3 Cortex-M启动流程
Cortex-M启动流程通常按以下步骤进行:
复位后,进入reset_handler,初始化通用寄存器为0;
调用系统初始化函数去配置UART、配置MPU等等;
进入C库的启动函数__main,完成一些初始化工作,像设置栈指针、初始化全局变量等,之后调用用户编写的main函数;
进入main主程序,完成主要操作;
进入WFI;
类似Cortex-A,步骤1~4以及步骤5在CPU验证中是固定的流程,不需要反复写,大部分验证人员只需要在步骤4的main函数中完成想要验证的功能。
4. Tube机制
SystemVerilog代码可以使用$display等内置的系统函数很方便的将信息打印到log上,但是C语言就不好弄。
常用的方法是Tube机制,把将要打印的字符串写到UART口上,UART上对接的组件会一直监控出现在UART口上的二进制数据,并把它们转成ASIIC码,然后调用SystemVerilog的$display函数打印到log上。
总得来说,还是借用了SystemVerilog的系统函数来打印的。
5. Testcase结束机制
对于只使用SystemVerilog和UVM环境的验证同学可能有疑问,Testcase结束不就很简单吗,直接调用$stop或drop_objection就ok了。但对于包含CPU运行的环境来说就不一样了,CPU执行的是C语言,从Memory中取值执行,验证环境不好监控它是否执行完毕,这就需要CPU发出一些可以被验证环境捕捉到的信号,用于表示CPU执行的状态。
一种常用的方法是CPU在执行完之后,往UART口写某些特定字符。UART口连接的监控组件如果解析到这些字符,将字符含义传达给验证环境。
同理,如果有多个CPU,那么需要UART监控多个CPU都往UART写完某些字符后,再使用event或全局变量等触发一个事件,UVM等到这个事件,再执行相应动作。
IC工程师技术盛会研讨会报名通知
从功率到 AI 的全面芯片测试论坛
来源:小玉科技频道