学过C语言都知道,在程序中添加打印信息有助于我们追踪程序执行的情况。特别是debug的时候,打印一些log信息对快速定位到问题非常有帮助。
(资料图)
怎么在SOC验证的C代码中打印字符串呢?用printf ?
下面,我们来试一下:
执行结果:
没有出现 Hello world。这种结果是符合预期的。C code 通过GCC编译生成bin文件然后送到CPU中按指令进行执行。我们看下这段代码编译出来的指令是什么?
这里 printf 编译出来是jump到一个puts的函数里面。puts函数又是什么呢?
puts 又跳到 _puts_r ,依次下去,由printf 编译出了一系列的指令代码。由于CPU最终综合成版图,因此在CPU的RTL代码中不会存在读到某条指令打印一个字符串的功能。所以单纯的调用printf 并不会在log中打印字符串信息。
如何实现打印?
两个思路,第一个思路,在SOC的TB里面增加一个CPU bus的monitor,我们在monitor中实现一个功能,当看到特定地址,特定数据的时候,开始收集要打印的字符串,当看到特定地址,另外一个特定数据的时候,结束字符串的收集,并将收集到字符串打印。
以下是我们在一个project中看到特殊数据 24’hdddd_11xx 开始收集字符串。
这样,我们可以在c里面实现一个打印字符串的函数。
通过上面这种手段,我们巧妙的将C语言的打印和 verilog的$display 打印连接起来。我们来看看效果
Hello World 打印出来了。
我们再看看 puts编译后的代码是什么?
这次 puts并没有跳转到_puts_r ,而是向特定地址发送特定数据表示开始,然后传输字符串,并以特定数据结束。当我们的monitor检查到这些特殊的数据时就会打印出log信息。
上面打印的方式可以解决在SOC验证环境中打印字符串的问题,但是在芯片流片回来之后,在C中调用上述函数还能打印吗?显然是不可以的,因为这个时候外部的monitor都没有了,更别说不能综合的display函数等。
下面介绍一种更加普遍的使用方法。我们在嵌入式硬件开发的过程中经常用到串口调试工具。
通过简单的几根线与电脑连接,然后用串口调试助手就能将SOC和电脑调试界面连接起来。
因此,在我们SOC验证环境中集成UART的slave device,在UART device收到数据后,打印出字符串信息是一个很好的选择。
为此,我们通过向uart device写字符串的形式,然后在UART device中实现打印功能。
我们来测试下用上面这种方式打印的效果,prints 是我们向uart 发送字符串的函数。
下面是执行效果:
同样实现了打印,而且这种打印方式在后续芯片流片回来之后可以通过串口调试 查看打印的信息。