2025-10-27
- 一生一芯
- 2025-10-28
- 44热度
- 0评论
发现一个奇怪的现象,timer返回值发生在回调函数被调用之前,这样应用程序永远没法获得最新的时间。
原先nemu的timer回调函数如下
<span class="line"><span style="color: #0000FF">static</span>
<span style="color: #000000"> </span>
<span style="color: #0000FF">void</span>
<span style="color: #000000"> </span>
<span style="color: #795E26">rtc_io_handler</span>
<span style="color: #000000">(</span>
<span style="color: #0000FF">uint32_t</span>
<span style="color: #000000"> </span>
<span style="color: #001080">offset</span>
<span style="color: #000000">, </span>
<span style="color: #0000FF">int</span>
<span style="color: #000000"> </span>
<span style="color: #001080">len</span>
<span style="color: #000000">, </span>
<span style="color: #0000FF">bool</span>
<span style="color: #000000"> </span>
<span style="color: #001080">is_write</span>
<span style="color: #000000">) {</span></span>
<span class="line"><span style="color: #000000"> </span>
<span style="color: #795E26">assert</span>
<span style="color: #000000">(offset == </span>
<span style="color: #098658">0</span>
<span style="color: #000000"> || offset == </span>
<span style="color: #098658">4</span>
<span style="color: #000000">);</span></span>
<span class="line"><span style="color: #000000"> </span>
<span style="color: #AF00DB">if</span>
<span style="color: #000000"> (!is_write && offset == </span>
<span style="color: #098658">4</span>
<span style="color: #000000">) {</span></span>
<span class="line"><span style="color: #000000"> </span>
<span style="color: #0000FF">uint64_t</span>
<span style="color: #000000"> us = </span>
<span style="color: #795E26">get_time</span>
<span style="color: #000000">();</span></span>
<span class="line"><span style="color: #000000"> </span>
<span style="color: #001080">rtc_port_base</span>
<span style="color: #000000">[</span>
<span style="color: #098658">0</span>
<span style="color: #000000">] = (</span>
<span style="color: #0000FF">uint32_t</span>
<span style="color: #000000">)us;</span></span>
<span class="line"><span style="color: #000000"> </span>
<span style="color: #001080">rtc_port_base</span>
<span style="color: #000000">[</span>
<span style="color: #098658">1</span>
<span style="color: #000000">] = us >> </span>
<span style="color: #098658">32</span>
<span style="color: #000000">;</span></span>
<span class="line"><span style="color: #000000"> </span>
<span style="color: #795E26">printf</span>
<span style="color: #000000">(</span>
<span style="color: #A31515">"Timer:</span>
<span style="color: #001080">%u</span>
<span style="color: #A31515">,</span>
<span style="color: #001080">%u</span>
<span style="color: #EE0000">\n</span>
<span style="color: #A31515">"</span>
<span style="color: #000000">,</span>
<span style="color: #001080">rtc_port_base</span>
<span style="color: #000000">[</span>
<span style="color: #098658">1</span>
<span style="color: #000000">],</span>
<span style="color: #001080">rtc_port_base</span>
<span style="color: #000000">[</span>
<span style="color: #098658">0</span>
<span style="color: #000000">]);</span></span>
<span class="line"><span style="color: #000000"> }</span></span>
<span class="line"><span style="color: #000000">}</span></span>代码第3行表示读高地址时才更新时间,这样的问题是如果只读时间的低32位则时间就永远是初始时间,去掉地址的判断,把第3行改成下面的代码
<span class="line"><span style="color: #000000">...</span></span>
<span class="line"><span style="color: #AF00DB">if</span>
<span style="color: #000000">(!is_write)</span></span>
<span class="line"><span style="color: #000000">...</span></span>系统就可以正常工作了。这里其实我早就注意到了,对timer工作方式也理解了,但是竟然一直没觉得这样是不对的。
总结一下am-kernels中的程序或者这些benchmark是怎么运行的。首先am-kernels中的程序可以称之为应用程序,这些程序是用C语言写的,用riscv工具链编译成可执行程序后需要一个“机器”来执行这些程序(当然因为没有操作系统,实际上执行的是bin文件)。NEMU就是执行这个程序的机器,NPC也是执行这个而程序的机器。一开始我觉得有点乱是因为NEMU和应用程序都是C语言,到底怎么执行起来的?NEMU是C语言编写的模拟器,编译成可执行文件后在Linux机器上执行,也就是在Ubuntu系统上执行。NEMU程序读取riscv工具编译出的应用程序bin文件然后执行bin文件里的指令。NEMU的好处是这个机器内部对我们完全是透明的,如果我们要debug应用程序,可以让NEMU进入单步执行模式,通过前面实现的各种基础设施可以获取当前NEMU的状态。如果我们要debug NEMU,就要用Linux系统上的gdb等工具。
NEMU里的代码是用来模拟硬件的,包括timer。因为不可能一直更新时间,所以Timer更新时间采用了回调函数的方式:如果用户程序读取timer的寄存器,则这个读取动作会调用timer里的更新函数更新timer的时间寄存器然后返回。这部分代码如下
<span class="line"><span style="color: #267F99">word_t</span>
<span style="color: #000000"> </span>
<span style="color: #795E26">map_read</span>
<span style="color: #000000">(</span>
<span style="color: #267F99">paddr_t</span>
<span style="color: #000000"> </span>
<span style="color: #001080">addr</span>
<span style="color: #000000">, </span>
<span style="color: #0000FF">int</span>
<span style="color: #000000"> </span>
<span style="color: #001080">len</span>
<span style="color: #000000">, IOMap *</span>
<span style="color: #001080">map</span>
<span style="color: #000000">) {</span></span>
<span class="line"><span style="color: #000000"> </span>
<span style="color: #795E26">assert</span>
<span style="color: #000000">(len >= </span>
<span style="color: #098658">1</span>
<span style="color: #000000"> && len <= </span>
<span style="color: #098658">8</span>
<span style="color: #000000">);</span></span>
<span class="line"><span style="color: #000000"> </span>
<span style="color: #795E26">check_bound</span>
<span style="color: #000000">(map, addr);</span></span>
<span class="line"><span style="color: #000000"> </span>
<span style="color: #267F99">paddr_t</span>
<span style="color: #000000"> offset = addr - </span>
<span style="color: #001080">map</span>
<span style="color: #000000">-></span>
<span style="color: #001080">low</span>
<span style="color: #000000">;</span></span>
<span class="line"><span style="color: #000000"> </span>
<span style="color: #795E26">invoke_callback</span>
<span style="color: #000000">(</span>
<span style="color: #001080">map</span>
<span style="color: #000000">-></span>
<span style="color: #001080">callback</span>
<span style="color: #000000">, offset, len, </span>
<span style="color: #0000FF">false</span>
<span style="color: #000000">);</span>
<span style="color: #008000"> // prepare data to read</span></span>
<span class="line"><span style="color: #000000"> </span>
<span style="color: #267F99">word_t</span>
<span style="color: #000000"> ret = </span>
<span style="color: #795E26">host_read</span>
<span style="color: #000000">(</span>
<span style="color: #001080">map</span>
<span style="color: #000000">-></span>
<span style="color: #001080">space</span>
<span style="color: #000000"> + offset, len);</span></span>
<span class="line"><span style="color: #000000"> </span>
<span style="color: #AF00DB">return</span>
<span style="color: #000000"> ret;</span></span>
<span class="line"><span style="color: #000000">}</span></span>
CNEMU将用户程序译码之后,如果涉及内存操作则会调用vaddr_read和vaddr_write,而这两个函数会分别调用paddr_read和paddr_write,如果生成NEMU时开启了添加Device选项,则paddr_read和paddr_write会调用mmio_read和mmio_write,mmio_read和mmio_write最终调用的就是map_read和map_write。
尝试运行demo的程序,出现了取指令错误的问题

打开反汇编文件发现这里并没有错误,而且NEMU取得的指令发生了错位,错位了1个字节。

GPU似乎还没实现完全?先不研究demo了,继续往下做