Depurando
Depurar hardaware (debugar) não é uma tarefá fácil, o problema pode estar em vários lugares diferentes: Componente queimando, solda com mal contato, erros no projeto de hardware, erro no software, clock com jiter ..... A lista de onde um problema pode estar é enorme e envolve várias áreas.
Aqui na disciplina vamos assumir uma lista menor de problemas, pois iremos eliminar que a placa pode estar com defeito (ou que não foi bem projetada) e que haja algum defeito na configuração do Quartus. Basicamente os problemas podem ser:
- No entendimento da logica
- Na transcrição de uma lógica combinacional/ sequencial para RTL (portas lógicas)
- No uso de recursos do MyHDL
Com o MyHDL conseguimos depurar um módulo de diversas maneiras e em diferentes camadas. Como estamos no ambiente do python, conseguimos inserir prints
ou usar breakpoints()
e acompanhar a simulação passo a passo. Podemos também gerar um diagrama de forma de ondas, que é muito utilizado para a depuração de hardware.
Para entendermos o processo iremos usar como exemplo o módulo fullAdder
que está em uso pelo adder2bits
do lab anterior.
Podemos inserir prints nos componentes a fim de ajudar no desenvolvimento do mesmo. Temos que entender que o print
não é sintetizável (não vai para a FPGA) e está limitado a apenas inputs
e sinais
internos do módulo, não podemos usar o print em outputs
.
Por exemplo, se desejarmos exibir o valor da saída soma
do halfAdder
, poderíamos inserir um print, mas como soma
é uma saída, vamos ter um erro:
@block
def halfAdder(a, b, soma, carry):
@always_comb
def comb():
soma.next = a ^ b
carry.next = a & b
print(soma) # (1)
return instances()
print
nosoma
que é uma saída, não podemos fazer isso!
myhdl.AlwaysCombError: signal ({'soma'}) used as inout in always_comb function argument
Para solucionar esse problema podemos criar um sinal interno auxiliar (que será visível como entrada e saída):
@block
def halfAdder(a, b, soma, carry):
s_soma = Signal(bool())
@always_comb
def comb():
s_soma = a ^ b
soma.next = s_soma
carry.next = a & b
print(s_soma)
return instances()
Info
Notem que nesse caso não usamos s_soma.next = a ^ b
, se fizermos
Agora se executarmos o teste com pytest -k halfAdder -s
, -s ativa o print para o terminal, iremos obter o resultado da soma
a cada interação do teste:
False
True
True
False
Exercise
breakpoint
Uma outra opção muito poderosa que possuímos é de utilizarmos breakpoint
no código, para isso basta adicionar breakpoint()
onde você deseja interromper a execução do código,e então executar novamente o teste.
@block
def halfAdder(a, b, soma, carry):
s = Signal(bool())
c = Signal(bool())
@always_comb
def comb():
breakpoint()
s = a ^ b
c = a & b
soma.next = s
carry.next = c
print("a: %s b: %s | s: %s c: %s" % (bin(a), bin(b), bin(s), bin(c)))
return instances()
Quando o programar atingir a linha do breakpoint. Nesse momento podemos usar uma série de recursos, vamos ver os mais importantes:
print(a)
: Você pode imprimir o valor de qualquer variável ou operaçãon
: (next) Podemos executar linha a linha o programac
: (continue) Podemos liberar a execução do programa até ele encontrar um novo breakpoint ou finalizarw
(where) Exibi informações do local do breakpoint
Exercise
Exercise
wave
Como as coisas em hardware acontecem simultaneamente fica difícil visualizar o que está acontecendo em todo o projeto, como alternativa podemos gerar uma forma de onda do hardware e visualizar o que está acontecendo com os sinais.
Note que na pasta 2-ula
foi gerado um arquivo chamado de adder2bits.vcd
, esse arquivo possui a forma de onda do teste. Para visualizarmos iremos usar o programa gtkwave
. No terminal, execute:
Terminal
- gtkwave adder2bits.vcd
Todo
Adicionar vídeo de como usar o gtkwave