前言
本文主要解决C906在仿真过程中,Printf不可以正常在终端打印的BUG。
(最近也在做基于C906的Linux系统,感兴趣的可以点个star
https://github.com/sususjysjy/Linux-on-c906-with-litex.git)
一、Open-C906
最近要构建在Riscv上运行的Linux系统,开源的Riscv核本就不多,还需要同时满足有MMU的要求。Rocket Chip、Vexriscv、Xiangshan都是不错的选择,可惜都是Spinal或者Scala,实在是不太会,只能使用平头哥的开源CPU。
开源的带有MMU的只有C开头的核,所以权衡资源,最终选择了C906.
二、C906仿真环境
平头哥仿真平台的搭建别的博主已经讲解很详细了,我这里主要说一下搭建后的CASE例程。
1.脚本修改
首先看MAKEFILE,C906默认的sim软件是iverilog,但是编译速度太慢了,所iverilog改为vcs进行编译。
################################################################################
# Simulation related
################################################################################
SIM = iverilog
DUMP = off
//修改后
################################################################################
# Simulation related
################################################################################
SIM = vcs
DUMP = on
2.CASE例程
可以先看一下C906的CASE。
我们跑一下coremark跑分,可以看到终端结果。
可以看到,仿真成功,但是终端没有任何输出,去看一下coremark源文件,是否有printf内容。
#define FREQ 100000000
vtimer_end= get_vtimer();
vcycles = vtimer_end - vtimer_start;
vcycles = vcycles/iterations;
printf ("\nVCUNT_SIM: CoreMark has been run %d times, one times cost %d cycles !\n",iterations,vcycles);
float score;
// score = FREQ/(float)vcycles;
// printf ("\nVCUNT_SIM: CoreMark 1.0 : %f iterations/sec\n",score); //CoreMark = iterations of a sec
score = 1000000/(float)vcycles; //to relieve relations with FREQ
printf ("\nVCUNT_SIM: CoreMark 1.0 : %f (iterations/sec)/MHz\n",score); //CoreMark = iterations of a sec
sim_end();
代码中是有对跑分结果做输出,但是终端没有正确打印,那么我们需要追溯printf底层定义的打印寄存器地址是什么。可以看到是0x6000fff8,同时,我们也需要找tb中规定的打印地址是否相同。
int fputc(int ch, FILE *stream)
{
asm(
"li x13, 0x6000fff8 \n\t"
"sw %0, 0(x13) \n\t"
: :"r" (ch): "x13" );
}
else if((cpu_awlen[3:0] == 4'b0) &&
(cpu_awaddr[31:0] == 32'h10015000) &&
cpu_wvalid)
这里其实就发现有问题,底层lib定义的地址是 0x6000fff8,而axi总线读数据所监测的地址是 0x10015000,两个是无法对应的,所以执行printf时,没有去正确地址的寄存器去读地址,自然终端不会有输出。
3.BUG修改
所以首先想到的是将两者地址改为相同即可,我们均改为0x10015000,重新运行CASE。
很奇怪,任然没有打印。
检查原因,打印的地址不能是tb中的地址,也不能是c910核心使用的地址。函数的写入fputc
必须到达顶部,而不会在缓存处停止(因此它必须位于不可缓存区域)。手册上说,当不使用虚拟内存时,PMA设置可以在C906_RTL_FACTORY/gen_rtl/mmu/rtl/sysmap.h
在那里,我们看到直到0x8fffffff
,该区域都是可缓存的(c910 的设置不同)。然后,直到0xbfffffff
,它是不可缓存的。
所以我们找到了原因,打印的地址要将其定义在不可缓存区域,所以大于0x8fffffff,我们将打印地址设置为0x90000000,重新运行CASE。
ok,可以正常在终端输出!!