A ideia central do DiffTest: Para duas implementações baseadas na mesma especificação, dada a mesma entrada definida, seu comportamento deve ser consistente. Voltando ao design do processador, para as duas implementações de acordo com o manual do riscv, dado o mesmo programa correto, suas mudanças de estado (registros, memória) devem ser consistentes para as duas implementações:
Um deles é a nossa CPU;
Alternativamente, escolha um simulador como implementação de referência. Cada vez que ambas as partes terminam de executar uma instrução, elas verificam o status de seus respectivos registros e memória. Se acharem que o status é inconsistente, elas imediatamente reportam um erro e interrompem a execução do programa cliente (equivalente a fazer um julgamento de afirmação para). cada instrução).
DiffTest = Método de verificação comportamental em nível de comando online
Online = Verifique durante a execução do programa
Nível de instrução = cada instrução executada é verificada
Pode converter qualquer programa em testes de nível de instrução e afirmar status
Programas de suporte que não terão fim, como SO
Não há necessidade de saber o resultado do procedimento com antecedência
Porque estamos comparando o comportamento da execução da instrução, não a semântica do programa
Os maiores usos do DiffTest são:Quando ocorrem erros de decodificação ou execução após a execução de centenas ou milhares de instruções, como encontramos rapidamente a primeira instrução de erro?
Neste artigo, escolhemos o seguinte como exemplo para ilustrar:
QEMU como objeto de referência (REF)
NEMU como cobaia (DUT)
Claro, se você precisar testar o hardware do processador, o processador também poderá ser usado como DUT.
2 DiffTest suportado por NEMU
make menuconfig
1
Entre em Teste e Depuração -> Habilitar teste diferencial -> Design de referência, como segue:
Quando NEMU é usado para DUT, você pode escolher 5 modos de simulador como simulador de referência REF.
QEMU, modo de biblioteca dinâmica, o código está localizado em NEMU/tools/qemu-dl-diff/
QEMU, modo Socket, o código está localizado em NEMU/tools/qemu-socket-diff/
KVM, o código está localizado em NEMU/tools/kvm-diff/
UEM NE
ESPINHO
Para os três últimos, o autor não fez nenhuma pesquisa específica, portanto este artigo não irá apresentá-los.
3 QEMU cria REF (modo de biblioteca dinâmica)
Você pode alterar NEMU/ferramentas/qemu-dl-diff/, compilado na biblioteca dinâmica riscv64-qemu-so. A relação entre NEMU, bibliotecas dinâmicas e QEMU:
Biblioteca dinâmica: riscv64-qemu-so, que exporta a série difftest_xx de interfaces de função.
QEMU: No arquivo executável qemu-system-riscv64, existem interfaces de função das séries cpu_xx, gdb_xx e qemu_xx.
NEMU: O programa interpretador riscv64-nemu chama a biblioteca dinâmica, que então chama o QEMU.
processo específico:
O programa executável NEMU riscv64-nemu-interpreter carrega riscv64-qemu-so chamando a função dlopen e analisa os símbolos de função da série difftest_xx para chamadas subsequentes.
Então, NEMU chama a função difftest_init para inicializar.
Na função difftest_init, a função dlopen será chamada novamente para carregar o arquivo executável qemu-system-riscv64 e analisar as séries de símbolos de função cpu_xx, gdb_xx e qemu_xx. Esses símbolos de função são, na verdade, o código de implementação subjacente da série de funções difftest_xx. .
No arquivo qemu-system-riscv64, a função analisada é a função principal e, em seguida, a função difftest_init a chamará para iniciar o programa qemu.
Então, se tudo estiver normal, você pode chamar a função qemu para comparar os resultados das instruções.
4 QEMU para REF (modo Socket)
Você pode alterar NEMU/ferramentas/qemu-socket-diff/, compilado na biblioteca dinâmica riscv64-qemu-so. A relação entre NEMU, bibliotecas dinâmicas e QEMU:
Biblioteca dinâmica: riscv64-qemu-so, que exporta a série difftest_xx de interfaces de função.
QEMU: O arquivo executável qemu-system-riscv64 possui interfaces de função das séries cpu_xx e gdb_xx.
NEMU: O programa interpretador riscv64-nemu chama a biblioteca dinâmica. A biblioteca dinâmica envia um pacote de comando através do soquete, o QEMU o analisa e decide qual função chamar para execução com base no comando específico.
processo específico:
O programa executável NEMU riscv64-nemu-interpreter carrega riscv64-qemu-so chamando a função dlopen e analisa os símbolos de função da série difftest_xx para chamadas subsequentes.
Então, NEMU chama a função difftest_init para inicializar.
Na função difftest_init, um processo filho bifurcará() e iniciará o QEMU chamando a função execlp enquanto o processo pai continua a ser executado, conecta-se ao QEMU por meio do soquete e chama a função init_isa para inicializar.
Então, se tudo estiver normal, você pode comparar os resultados do comando através do soquete.