NEMU DiffTest基本原理


本文属于 《RISC-V指令集差分测试(DiffTest)系列教程》之一,欢迎查看其它文章。

1 DiffTest原理简述

DiffTest核心思想: 对于根据同一规范的两种实现, 给定相同的有定义的输入, 它们的行为应当一致。
回到处理器设计,对于根据riscv手册的两种实现, 给定相同的正确程序, 它们的状态变化(寄存器、内存),应当一致,两种实现:

  • 其中一种,是我们的CPU;
  • 另一种,选一个模拟器作为参考实现。
    在这里插入图片描述
    双方每执行完一条指令,就检查各自的寄存器和内存的状态,如果发现状态不一致,就马上报告错误,停止客户程序的执行(相当于对每一条指令做assert判断)。
  • DiffTest = 在线指令级行为验证方法
    • 在线 = 边跑程序边验证
    • 指令级 = 执行的每条指令都验证
  • 能把任意程序转化为指令级别的测试, 对状态进行断言
    • 支持不会结束的程序, 例如OS
  • 无需提前得知程序的结果
    • 因为我们对比的是指令执行的行为, 而不是程序的语义

DiffTest最大的用处是:当跑了几百,几千条指令出现译码或执行bug,我们如何快速找出第一条出错的指令,这是一个地狱级的难度。

本文中,我们选择以下,为例进行说明:

  • QEMU作为参考对象(REF)
  • NEMU作为测试对象(DUT)

当然,如果需要测试处理器硬件,那处理器也可以作为DUT。

2 NEMU支持的DiffTest

make menuconfig

进入Testing and Debugging -> Enable differential testing -> Reference design,如下:

在这里插入图片描述
NEMU作DUT时,可以选择5种方式的模拟器,作为参考模拟器REF。

  • QEMU,动态库方式,代码位于NEMU/tools/qemu-dl-diff/
  • QEMU,Socket方式,代码位于NEMU/tools/qemu-socket-diff/
  • KVM,代码位于NEMU/tools/kvm-diff/
  • NEMU
  • SPIKE

对于后面三种,楼主没有具体研究,因此本文也不作介绍。

3 QEMU作REF(动态库方式)

可以将NEMU/tools/qemu-dl-diff/,编译为动态库riscv64-qemu-so。
NEMU、动态库、QEMU之间的关系:
在这里插入图片描述

  • 动态库:riscv64-qemu-so,导出了difftest_xx系列函数接口。
  • QEMU:qemu-system-riscv64可执行文件中,有cpu_xx、gdb_xx以及qemu_xx系列函数接口。
  • NEMU:riscv64-nemu-interpreter程序,调用动态库,动态库再调用QEMU。

具体流程:

  • NEMU可执行程序riscv64-nemu-interpreter,通过调用dlopen函数加载riscv64-qemu-so,并将difftest_xx系列函数符号解析出来,以备后续调用。
  • 然后,NEMU调用difftest_init函数,进行初始化。
  • 在difftest_init函数中,会再次调用dlopen函数,去加载qemu-system-riscv64可执行文件,并解析cpu_xx、gdb_xx以及qemu_xx系列函数符号,这些函数符号,其实就是difftest_xx系列函数的底层实现代码。
  • 从qemu-system-riscv64文件中,解析的函数,就有main函数,随后difftest_init函数就会调用它,以启动qemu程序。
  • NEMU调用difftest_memcpy函数,将benos_payload.bin,拷贝到QEMU中0x80000000地址处,表示NEMU的二进制镜像与QEMU同步了。
  • NEMU调用difftest_regcpy函数,将CPU寄存器,拷贝到QEMU中,表示NEMU的寄存器与QEMU同步了,如下图所示。
  • 随后,如果一切正常的话,就可以调用qemu函数,以实现指令结果比对了。

在这里插入图片描述

4 QEMU作REF(Socket方式)

可以将NEMU/tools/qemu-socket-diff/,编译为动态库riscv64-qemu-so。
NEMU、动态库、QEMU之间的关系:
在这里插入图片描述

  • 动态库:riscv64-qemu-so,导出了difftest_xx系列函数接口。
  • QEMU:qemu-system-riscv64可执行文件中,有cpu_xx、gdb_xx系列函数接口。
  • NEMU:riscv64-nemu-interpreter程序,调用动态库,动态库通过socket发送命令数据包,QEMU接收到数据包并解析,根据具体命令,决定调用哪个函数执行。

具体流程:

  • NEMU可执行程序riscv64-nemu-interpreter,通过调用dlopen函数加载riscv64-qemu-so,并将difftest_xx系列函数符号解析出来,以备后续调用。
  • 然后,NEMU调用difftest_init函数,进行初始化。
  • 在difftest_init函数中,会fork()一个子进程出来,通过调用execlp函数启动QEMU;而父进程继续执行,通过socket连接QEMU,调用init_isa函数初始化。
  • NEMU调用difftest_memcpy函数,将benos_payload.bin,拷贝到QEMU中0x80000000地址处,表示NEMU的二进制镜像与QEMU同步了。
  • NEMU调用difftest_regcpy函数,将CPU寄存器,拷贝到QEMU中,表示NEMU的寄存器与QEMU同步了,如下图所示。
  • 随后,如果一切正常的话,就可以通过socket,以实现指令结果比对了。

在这里插入图片描述

二进制和寄存器同步,与动态库方式区别就是,这里是通过socket来完成的。


参考文档:

  • 18
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
项目:使用AngularJs编写的简单 益智游戏(附源代码)  这是一个简单的 javascript 项目。这是一个拼图游戏,也包含一个填字游戏。这个游戏玩起来很棒。有两个不同的版本可以玩这个游戏。你也可以玩填字游戏。 关于游戏 这款游戏的玩法很简单。如上所述,它包含拼图和填字游戏。您可以通过移动图像来玩滑动拼图。您还可以选择要在滑动面板中拥有的列数和网格数。 另一个是填字游戏。在这里你只需要找到浏览器左侧提到的那些单词。 要运行此游戏,您需要在系统上安装浏览器。下载并在代码编辑器中打开此项目。然后有一个 index.html 文件可供您修改。在命令提示符中运行该文件,或者您可以直接运行索引文件。使用 Google Chrome 或 FireFox 可获得更好的用户体验。此外,这是一款多人游戏,双方玩家都是人类。 这个游戏包含很多 JavaScript 验证。这个游戏很有趣,如果你能用一点 CSS 修改它,那就更好了。 总的来说,这个项目使用了很多 javascript 和 javascript 库。如果你可以添加一些具有不同颜色选项的级别,那么你一定可以利用其库来提高你的 javascript 技能。 演示: 该项目为国外大神项目,可以作为毕业设计的项目,也可以作为大作业项目,不用担心代码重复,设计重复等,如果需要对项目进行修改,需要具备一定基础知识。 注意:如果装有360等杀毒软件,可能会出现误报的情况,源码本身并无病毒,使用源码时可以关闭360,或者添加信任。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

百里杨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值