Verilog sempre bloquear
Um
always
bloco é um dos procedimentos blocos em Verilog. As instruções dentro de um bloco sempre são executadas sequencialmente. Sintaxe
always @ (event)
[statement]
always @ (event) begin
[multiple statements]
end
O
always
bloco é executado em algum evento particular. O evento é definido por uma lista de sensibilidade. O que é a lista de sensibilidade?
Uma sensibilidade list é a expressão que define quando o bloco always deve ser executado e é especificado após o
@
operador entre parênteses ( )
. Esta lista pode conter um ou um grupo de sinais cuja mudança de valor executará o bloco sempre. No código mostrado abaixo, todas as instruções dentro do
always
bloco é executado sempre que o valor dos sinais a ou b mudar.
// Execute always block whenever value of "a" or "b" change
always @ (a or b) begin
[statements]
end
Para que serve o bloco sempre ?
Um
always
bloco pode ser usado para realizar elementos combinacionais ou sequenciais. Um elemento sequencial como o flip-flop torna-se ativo quando é fornecido com um relógio e reinicializado. Da mesma forma, um bloco combinacional torna-se ativo quando um de seus valores de entrada é alterado. Esses blocos de hardware estão todos trabalhando simultaneamente independentes uns dos outros. A conexão entre cada um é o que determina o fluxo de dados. Para modelar esse comportamento, um always
bloco é feito como um processo contínuo que é acionado e executa alguma ação quando um sinal dentro da lista de sensibilidade se torna ativo. No exemplo a seguir, todas as instruções dentro do bloco always são executadas em cada aresta positiva do sinal clk.
// Execute always block at positive edge of signal "clk"
always @ (posedge clk) begin
[statements]
end
O que acontece se não houver uma lista de sensibilidade?
O
always
bloco se repete continuamente ao longo da duração de uma simulação. A lista de sensibilidade traz um certo senso de tempo, ou seja, sempre que qualquer sinal na lista de sensibilidade muda, o bloco sempre é acionado. Se não houver instruções de controle de tempo dentro de um bloco sempre, a simulação será interrompida devido a um loop infinito de atraso zero! Exemplo
O exemplo mostrado abaixo é um bloco sempre que tenta inverter o valor do sinal clk. A instrução é executada a cada 0 unidades de tempo. Portanto, ele é executado para sempre devido à ausência de um atraso na instrução.
// always block is started at time 0 units
// But when is it supposed to be repeated ?
// There is no time control, and hence it will stay and
// be repeated at 0 time units only. This continues
// in a loop and simulation will hang !
always clk = ~clk;
Mesmo que a lista de sensibilidade esteja vazia, deve haver alguma outra forma de atraso de tempo. O tempo de simulação é avançado por uma declaração de atraso dentro do
always
construir como mostrado abaixo. Agora, a inversão do relógio é feita a cada 10 unidades de tempo.
always #10 clk = ~clk;
Observação: Atrasos explícitos não são sintetizados em portas lógicas!
Portanto, o código de design Verilog real sempre exige uma lista de sensibilidade.
Exemplo de projeto de elemento sequencial
O código mostrado abaixo define um módulo chamado tff que aceita uma entrada de dados, clock e reset ativo-baixo. A saída é invertida sempre que d é encontrado como 1 na borda positiva do clock. Aqui, o
always
O bloco é acionado na borda positiva de clk ou na borda negativa de rstn. O que acontece na borda positiva do relógio?
Os seguintes eventos acontecem na borda positiva do clock e são repetidos para todas as bordas positivas do clock.
- Primeiro
if
bloco verifica o valor de reset ativo-baixo rstn - Se rstn for zero, a saída q deve ser redefinida para o valor padrão de 0
- Se rstn for um, significa que a redefinição não foi aplicada e deve seguir o comportamento padrão
- Se a etapa anterior for falsa:
- Verifique o valor de d e, se for um, inverta o valor de q
- Se d for 0, mantenha o valor de q
module tff (input d,
clk,
rstn,
output reg q);
always @ (posedge clk or negedge rstn) begin
if (!rstn)
q <= 0;
else
if (d)
q <= ~q;
else
q <= q;
end
endmodule
O que acontece na borda negativa da reinicialização?
Os eventos a seguir acontecem na borda negativa de rstn e acontecem em todas essas ocorrências.
- Primeiro
if
bloco verifica o valor de reset ativo-baixo rstn. Na borda negativa do sinal, seu valor é 0. - Se o valor de rstn for 0, significa que o reset é aplicado e a saída deve ser redefinida para o valor padrão de 0
- O caso em que o valor de rstn é 1 não é considerado porque o evento atual é borda negativa do primeiro
Exemplo de Design de Elemento Combinacional
Um
always
bloco também pode ser usado no projeto de blocos combinacionais. Por exemplo, o circuito digital a seguir representa uma combinação de três portas lógicas diferentes que fornecem uma determinada saída no sinal o. O código mostrado abaixo é um
module
com quatro portas de entrada e uma única porta de saída chamada o. O always
O bloco é acionado sempre que qualquer um dos sinais na lista de sensibilidade muda de valor. O sinal de saída é declarado como tipo reg
na lista de portas do módulo porque é usado em um bloco procedural. Todos os sinais usados em um bloco procedural devem ser declarados como do tipo reg
.
module combo ( input a,
input b,
input c,
input d,
output reg o);
always @ (a or b or c or d) begin
o <= ~((a & b) | (c^d));
end
endmodule
Veja que o sinal o torna-se 1 sempre que a expressão combinacional no RHS se torna verdadeira. Da mesma forma, o torna-se 0 quando RHS é falso.
Saída de simulação
Clique aqui para uma apresentação de slides com exemplo de simulação!
Verilog