在嵌入式处理器领域,衡量CPU性能最知名和常见的基准测试莫过于 CoreMark 与 Dhrystone。
- CoreMark: 专门用于衡量嵌入式系统中CPU(或微控制器MCU)性能的标准,于2009年由EEMBC开发。
- DMIPS: Dhrystone Million Instructions executed Per Second,主要用于测试系统的整数运算性能。
本文将结合瑞萨RA6M4开发板,提供一个详细的、基于e² studio开发环境的CoreMark移植教程,并分享关键的代码修改步骤。
CoreMark旨在取代过时的Dhrystone基准,成为行业标准。其测试代码完全用C语言编写,核心包含四种算法:列表处理(增删改查排序)、矩阵操作、状态机(校验数字)和CRC。开发者可以自由下载并移植到自己的平台运行,最终获得一个量化的性能分数。
首先,前往CoreMark官网下载官方源码:
https://www.eembc.org/coremark/index.php
解压后,我们主要关注以下核心文件:

移植所需的核心文件包括:
core_list_join.c
core_main.c
core_matrix.c
core_state.c
core_util.c
coremark.h
simple/core_portme.c
simple/core_portme.h
本文以RA6M4开发板为例,创建工程并选择正确的MCU型号。随后,将上述CoreMark源文件拷贝到工程的 src 文件夹下。

关键提示:e² studio的FSP框架会自动生成一个main.c,其中直接调用hal_entry()函数。由于hal_entry.c是自动生成且无法删除,我们需要将core_main.c中的全部内容复制到hal_entry.c里,并把main(void)函数重命名为void hal_entry(void)。

前期硬件功能准备:
- 配置UART串口:用于打印CoreMark结果。本文假设串口打印功能(例如
Uart0_printf)已调试完成。
- 配置定时器:设定一个1ms周期的定时器中断,用于精确计算CoreMark算法运行所耗费的时间。
移植后的关键代码修改步骤
1. 添加头文件
在 hal_entry.c 文件开头,加入串口打印功能所需的头文件。
#include “hal_data.h”
#include “stdio.h”
#include “uart_printf.h” // 你的串口打印头文件
#include “core_mark.h”

2. 初始化外设
在hal_entry函数的起始位置,添加打开GPIO和UART外设的代码。
void hal_entry(void)
{
/* TODO: add your own code here */
// ... 变量声明
/**********Added function start**********/
R_IOPORT_Open(&g_ioport_ctrl, &g_bsp_pin_cfg); /* GPIO open */
R_SCI_UART_Open(&g_uart0_ctrl, &g_uart0_cfg); /* UART open */
/**********Added function end**********/
// ... 后续代码
}

3. 修改 portable_init 函数
系统的时钟等初始化已在启动文件startup.c中完成,且此函数无参数传入,因此需要修改core_portme.c中的portable_init函数。主要改动是移除参数,并将内部的ee_printf替换为自己的串口打印函数(如Uart0_printf)。
修改前:

修改后:
portable_init(core_portable *p)
{
if (sizeof(ee_ptr_int) != sizeof(ee_u8 *)) {
Uart0_printf(“ERROR! Please define ee_ptr_int to a type that holds a \“pointer!\n”);
}
if (sizeof(ee_u32) != 4) {
Uart0_printf(“ERROR! Please define ee_u32 to a 32b unsigned type!\n”);
}
p->portable_id=1;
}

4. 修改计时相关代码
这是移植的核心,需要根据你使用的定时器修改时间获取函数。本例使用1ms定时器中断。
-
修改计时函数 (core_portme.c):

主要改动为:在start_time中启动定时器并清零计数器,在stop_time中停止定时器,get_time直接返回累加的Tick值。
-
简化时间相关宏定义:

仅需保留 #define EE_TICKS_PER_SEC (1000) (因为定时器1ms中断一次),其他与平台相关的宏可以注释或删除。
-
添加定时器中断回调函数:
在合适的位置(如hal_entry.c)定义定时器中断服务函数,用于累加全局变量Tick。
/***********Added time counter***********/
void Timer0_1ms_Callback(timer_callback_args_t *p_args)
{
if((p_args != NULL) && (p_args->event == TIMER_EVENT_CYCLE_END)) {
Tick++;
}
}
/***********************************************/

5. 调整迭代次数并声明Tick变量
为了保证测试的有效性,CoreMark要求程序运行时间至少大于10秒。你需要根据主频调整ITERATIONS的值。
在core_portme.c或core_portme.h中修改:
#define ITERATIONS (12000) // 根据实际情况调整此值
static uint32_t Tick; // 声明在计时函数中使用的全局变量

6. 设置编译器信息
在core_portme.h中,定义COMPILER_FLAGS宏,用于在结果中标识你的编译环境。
#ifndef COMPILER_FLAGS
#define COMPILER_FLAGS “FSP V2.3.0” // 替换为你的实际环境
#endif

7. 替换打印函数
在整个工程中,将CoreMark源码中默认的ee_printf()函数调用,全部替换为你自己的串口打印函数(例如Uart0_printf)。可以使用编辑器的“查找与替换”功能高效完成。
8. 使能e² studio的浮点数打印支持
e² studio的默认newlib-nano库配置不支持printf浮点数。需要手动开启此功能:
- 右键工程,选择
Properties。
- 进入
C/C++ Build -> Settings -> Tool Settings -> GNU ARM Cross C Linker -> Miscellaneous。
- 勾选
Use float with nano printf (-u_printf_float)。

运行测试与结果
完成以上所有修改并编译下载程序后,打开串口调试助手(波特率115200),复位开发板。你将看到CoreMark的测试结果输出。

结果中包含了关键的CoreMark/MHz分数(本例中约为355.84),以及算法正确性校验值。这为你评估MCU的计算机基础运算性能提供了一个权威的量化参考。
至此,基于瑞萨RA MCU的CoreMark移植就完成了。你可以将此框架应用到其他RA系列MCU上,只需根据具体型号调整时钟和引脚配置即可。如果在移植过程中遇到问题,欢迎在云栈社区的技术板块进行交流探讨。