La idea central de DiffTest: para dos implementaciones basadas en la misma especificación, dada la misma entrada definida, su comportamiento debe ser consistente. Volviendo al diseño del procesador, para las dos implementaciones según el manual de riscv, dado el mismo programa correcto, sus cambios de estado (registros, memoria) deben ser consistentes para las dos implementaciones:
Uno de ellos es nuestra CPU;
Alternativamente, elija un simulador como implementación de referencia. Cada vez que ambas partes terminan de ejecutar una instrucción, verifican el estado de sus respectivos registros y memoria. Si encuentran que el estado es inconsistente, inmediatamente informan un error y detienen la ejecución del programa cliente (equivalente a hacer un juicio de afirmación). cada instrucción).
DiffTest = Método de verificación de comportamiento a nivel de comando en línea
En línea = Verificar mientras se ejecuta el programa
Nivel de instrucción = cada instrucción ejecutada se verifica
Puede convertir cualquier programa en pruebas de nivel de instrucción y afirmar su estado.
Programas de soporte que no terminarán, como OS
No es necesario conocer de antemano el resultado del procedimiento.
Porque estamos comparando el comportamiento de ejecución de instrucciones, no la semántica del programa.
Los usos más importantes de DiffTest son:Cuando se producen errores de decodificación o ejecución después de ejecutar cientos o miles de instrucciones, ¿cómo encontramos rápidamente la primera instrucción errónea? Esta es una dificultad infernal.
En este artículo, elegimos el siguiente como ejemplo para ilustrar:
QEMU como objeto de referencia (REF)
NEMU como sujeto de prueba (DUT)
Por supuesto, si necesita probar el hardware del procesador, el procesador también se puede utilizar como DUT.
2 Prueba de diferencias compatible con NEMU
make menuconfig
1
Ingrese a Pruebas y depuración -> Habilitar pruebas diferenciales -> Diseño de referencia, de la siguiente manera:
Cuando se utiliza NEMU para DUT, puede elegir 5 modos de simulador como REF del simulador de referencia.
QEMU, modo de biblioteca dinámica, el código se encuentra en NEMU/tools/qemu-dl-diff/
QEMU, modo Socket, el código se encuentra en NEMU/tools/qemu-socket-diff/
KVM, el código se encuentra en NEMU/tools/kvm-diff/
NEMU
ESPIGA
Para los últimos tres, el autor no ha realizado ninguna investigación específica, por lo que este artículo no los presentará.
3 QEMU hace REF (modo de biblioteca dinámica)
Puedes cambiar NEMU/herramientas/diferencia qemu-dl/, compilado en la biblioteca dinámica riscv64-qemu-so. La relación entre NEMU, bibliotecas dinámicas y QEMU:
Biblioteca dinámica: riscv64-qemu-so, que exporta la serie difftest_xx de interfaces de funciones.
QEMU: en el archivo ejecutable qemu-system-riscv64, hay interfaces de funciones de las series cpu_xx, gdb_xx y qemu_xx.
NEMU: el programa riscv64-nemu-interpreter llama a la biblioteca dinámica, que luego llama a QEMU.
proceso específico:
El programa ejecutable NEMU riscv64-nemu-interpreter carga riscv64-qemu-so llamando a la función dlopen y analiza los símbolos de función de la serie difftest_xx para llamadas posteriores.
Luego, NEMU llama a la función difftest_init para inicializar.
En la función difftest_init, se llamará nuevamente a la función dlopen para cargar el archivo ejecutable qemu-system-riscv64 y analizar las series de símbolos de función cpu_xx, gdb_xx y qemu_xx. Estos símbolos de función son en realidad el código de implementación subyacente de la serie de funciones difftest_xx. .
Desde el archivo qemu-system-riscv64, la función analizada es la función principal, y luego la función difftest_init la llamará para iniciar el programa qemu.
Luego, si todo es normal, puede llamar a la función qemu para comparar los resultados de la instrucción.
4 QEMU para REF (modo Socket)
Puedes cambiar NEMU/herramientas/Diferencia entre sockets qemu/, compilado en la biblioteca dinámica riscv64-qemu-so. La relación entre NEMU, bibliotecas dinámicas y QEMU:
Biblioteca dinámica: riscv64-qemu-so, que exporta la serie difftest_xx de interfaces de funciones.
QEMU: el archivo ejecutable qemu-system-riscv64 tiene interfaces de funciones de las series cpu_xx y gdb_xx.
NEMU: el programa riscv64-nemu-interpreter llama a la biblioteca dinámica. La biblioteca dinámica envía un paquete de comando a través del socket QEMU recibe el paquete, lo analiza y decide qué función llamar para su ejecución en función del comando específico.
proceso específico:
El programa ejecutable NEMU riscv64-nemu-interpreter carga riscv64-qemu-so llamando a la función dlopen y analiza los símbolos de función de la serie difftest_xx para llamadas posteriores.
Luego, NEMU llama a la función difftest_init para inicializar.
En la función difftest_init, un proceso hijo bifurcará() e iniciará QEMU llamando a la función execlp mientras el proceso padre continúa ejecutándose, se conecta a QEMU a través del socket y llama a la función init_isa para inicializar.
Luego, si todo es normal, puedes comparar los resultados del comando a través del socket.