código Verilog simula mas não é executado como previsto em FPGA
Pergunta
Eu fiz uma simulação comportamental do meu código, e ele funciona perfeitamente. Os resultados são como é previsto. Quando eu sintetizar meu código e enviá-lo para uma 3e espartano FPGA e tentar analisar usando ChipScope, os resultados não são nem perto do que eu teria esperado. O que eu fiz de forma incorreta? http://pastebin.com/XWMekL7r
Solução
Seu problema é com linhas 13-16, onde você definir valores iniciais para os registos de estado:
reg [OUTPUT_WIDTH-1:0] previousstate = 0;
reg [OUTPUT_WIDTH-1:0] presentstate = 1;
reg [6:0] fib_number_cnt = 1;
reg [OUTPUT_WIDTH-1:0] nextstate = 1;
Este é um equivalente a escrever uma declaração "inicial" de atribuir esses valores, que não é synthesizable - não existe tal coisa como um valor padrão no hardware. Quando você colocar o seu projeto dentro de um FPGA, todos esses registros vai assumir valores aleatórios.
Em vez disso, você precisa para inicializar esses contadores / estados dentro do seu sempre bloquear, quando reinicialização é alta.
always @(posedge clk or posedge reset)
if (reset) begin
previousstate <= 0;
presentstate <= 1;
... etc ...
end
Resposta às perguntas de acompanhamento:
Quando você inicializar um código como esse, nada acontece em hardware - ele é completamente ignorado, como se você colocar em um comunicado $ display. Os saltos ferramenta de síntese sobre todas as construções só de simulação, enquanto geralmente dando-lhe algum tipo de aviso sobre isso (que realmente depende da ferramenta).
Agora, bloqueio e sem bloqueio questão exige uma resposta muito longa :). Vou encaminhá-lo para este papel de SNUG-2000, que é provavelmente o melhor papel já escrito sobre o assunto. Ele responde a sua pergunta, assim como muitos outros sobre o tema. Depois disso, você vai entender por que usar instruções de bloqueio na lógica seqüencial é considerado uma má prática, e por que seu código funciona bem com o bloqueio declarações de qualquer maneira.
http://cs.haifa.ac.il /courses/verilog/cummings-nonblocking-snug99.pdf
Mais respostas:
O "padrão" usual para a criação de lógica como o seu é ter dois sempre blocos, um que define a lógica, e uma definição da aleta. No primeiro caso, você usa o bloqueio declarações para implementar a lógica, e no último você trava (ou redefinir) o valor gerado. Então, algo como isto:
wire some_input;
// Main logic (use blocking statements)
reg state, next_state;
always @*
if (reset) next_state = 1'b0;
else begin
// your state logic
if (state) next_state = some_input;
else next_state = 1'b0;
end
// Flops (use non-blocking)
always @(posedge clock)
if (reset) state <= 1'b0;
else state <= next_state;
Note que eu estou usando um reset síncrono, mas você pode usar assíncrono, se necessário.
Outras dicas
Linhas 13-16 estão corretas. "Reg [6: 0] fib_number_cnt = 1;" não é o mesmo que usar declaração "inicial". Leia Xilinx síntese guia para descrição mais detalhada de como inicializar os registros.