Diferença entre atribuição de bloqueio e não bloqueio Verilog

15

Eu estava lendo esta página http://www.asic-world.com/verilog/verilog_one_day3.html quando me deparei com o seguinte:

Normalmente, temos que redefinir os flip-flops; assim, toda vez que o relógio faz a transição de 0 para 1 (posedge), verificamos se o reset é afirmado (redefinição síncrona) e continuamos com a lógica normal. Se olharmos atentamente, veremos que, no caso da lógica combinacional, tínhamos "=" para atribuição e, para o bloco seqüencial, tínhamos o operador "<=". Bem, "=" está bloqueando a atribuição e "<=" está bloqueando a atribuição. "=" executa o código sequencialmente dentro de um início / fim, enquanto o não bloqueador "<=" é executado em paralelo.

Eu tinha quase certeza de que as tarefas sem bloqueio eram seqüenciais enquanto as tarefas de bloqueio eram paralelas. Afinal, você pode fazer atribuições de bloqueio com instruções de atribuição fora dos blocos sempre, e todas elas são executadas em paralelo. Isso é um erro ou o comportamento é diferente dentro de um bloco always? E, se o comportamento for diferente dentro de um bloco always, as atribuições de não bloqueio podem ser feitas fora de um bloco always?

Void Star
fonte

Respostas:

21

tinha quase certeza de que as atribuições sem bloqueio eram seqüenciais enquanto as atribuições de bloqueio eram paralelas.

A atribuição de bloqueio é executada "em série" porque uma atribuição de bloqueio bloqueia a execução da próxima instrução até que ela seja concluída. Portanto, os resultados da próxima instrução podem depender da conclusão da primeira.

A atribuição sem bloqueio é executada em paralelo porque descreve as atribuições que ocorrem todas ao mesmo tempo. O resultado de uma declaração na 2ª linha não dependerá dos resultados da declaração na 1ª linha. Em vez disso, a 2ª linha será executada como se a 1ª linha ainda não tivesse acontecido.

O fóton
fonte
Então, e as instruções de atribuição? Eles estão em uma classe inteira própria?
Vazio Estrela
4
Sim, as assigninstruções ocorrem fora dos blocos always e geralmente são usadas para descrever a lógica combinatória (sem travamento) (enquanto os blocos sempre, com algumas exceções, descrevem a lógica seqüencial). AFAIK, assigninstruções sempre executam "em paralelo" sempre que seu LHS tiver uma alteração de valor.
O Photon
Ok ... Estou começando a ter a impressão de que o Verilog não é a linguagem mais elegante. Vai ser como aprender que C era.
Void Star
1
O Verilog foi projetado para "descrever" o hardware que já existe. Usá-lo como uma linguagem para projetar (sintetizar) hardware é um truque.
The Photon
4
Se o Verilog "como aprender C" for um problema, dê uma olhada no VHDL. Algumas pessoas têm preferências bastante fortes por um ou outro. Para alguns, o VHDL é muito detalhado. Para mim, é muito melhor pensar. (a semântica da atribuição de sinal / variável é muito mais clara que o bloqueio / não, por exemplo). stackoverflow.com/questions/13954193/… e sigasi.com/content/vhdls-crown-jewel Você pode preferir ou odiar. Mas vale a pena dar uma olhada.
Brian Drummond
6

As instruções de atribuição não são "bloqueadoras" ou "não bloqueadas", elas são "contínuas". A saída de uma instrução de atribuição é sempre igual à função especificada de suas entradas. As atribuições "bloqueio" e "não bloqueio" existem apenas dentro dos blocos sempre.

Uma atribuição de bloqueio entra em vigor imediatamente após ser processada. Uma atribuição sem bloqueio ocorre no final do processamento do "delta de tempo" atual.

Os blocos always podem ser usados ​​para modelar lógica combinatória ou seqüencial (o systemverilog tem always_comb e always_ff para tornar isso explícito). Ao modelar a lógica combinatória, geralmente é mais eficiente usar =, mas normalmente não importa.

Ao modelar a lógica seqüencial (por exemplo, sempre @ (posedge clk)), você normalmente usa asserções sem bloqueio. Isso permite determinar o "estado após o limite do relógio" em termos de "o estado antes do limite do relógio".

Às vezes, é útil usar atribuições de bloqueio em blocos sequenciais sempre como "variáveis". Se você fizer isso, há duas regras importantes a serem lembradas.

  1. Não acesse um registro definido com atribuições de bloqueio dentro de um bloco sempre seqüencial de fora do bloco sempre em que ele está atribuído.
  2. Não misture atribuições de bloqueio e não bloqueio ao mesmo registro.

A quebra dessas regras provavelmente resultará em falhas de síntese e / ou diferenças de comportamento entre simulação e síntese.

Peter Green
fonte
"" Não acesse um registro definido com atribuições de bloqueio dentro de um bloco sempre seqüencial de fora do bloco sempre em que ele está atribuído. "" Você pode explicar isso?
user125575
Os blocos sempre sequenciais diferentes não têm uma ordem definida. Portanto, a leitura de um conjunto "reg" com uma classificação de bloqueio em um bloco sempre de outro bloco sempre levará a um comportamento imprevisível.
Peter Green #
E mesmo que pareça funcionar em simulação, uma ferramenta de síntese deve analisar isso e dizer "não". Uso regs locais para esses vars intermediários e asseguro que eles sempre sejam atribuídos a cada relógio antes de serem lidos, para que nenhum 'armazenamento' seja implícito.
Greggo
IIRC pelo menos em quartus, é considerado apenas um aviso, não um erro.
Peter Green
5

O termo atribuição de bloqueio confunde as pessoas porque a palavra bloqueio parece sugerir lógica seqüencial no tempo. Mas, na lógica sintetizada , isso não significa isso , porque tudo opera em paralelo .

Talvez um termo menos confuso seja a atribuição imediata , que ainda diferenciaria os resultados intermediários da lógica combinacional das entradas para elementos de memória não transparentes (por exemplo, registros com clock), que podem ter atrasado a atribuição .

Do ponto de vista legalista, tudo funciona muito bem. De fato, você pode considerar =uma operação de bloqueio (sequencial no tempo), mesmo dentro de always_combsequências. No entanto, a distinção entre sequencial e paralelo não faz absolutamente nenhuma diferença neste caso, porque o always_combbloco é definido para repetir até que a sequência de instruções converja em um estado estável - que é exatamente o que o circuito do hardware fará (se atingir o tempo) requisitos).

O subconjunto sintetizável do Verilog (e especialmente o SystemVerilog) é extremamente simples e fácil de usar - depois de conhecer os idiomas necessários. Você apenas precisa superar o uso inteligente da terminologia associada aos chamados elementos comportamentais da linguagem.

nobar
fonte
Nos estilos de codificação comportamental ( em comparação com RTL ), a distinção entre bloqueio e não bloqueio pode ser relevante. Em alguns casos, a ferramenta de síntese pode ser capaz de inferir RTL funcionalmente equivalente a partir de projetos de componentes comportamentais.
Nobar
Obviamente, o modo procedural do SystemVerilog, aplicável especialmente a initialinstruções dentro de programblocos, usa a atribuição de bloqueio (sequencial de tempo) exclusivamente. Isso é útil para projeto testbench , mas geralmente não para a especificação RTL.
dec