Diferença entre atribuição bloqueadora e não bloqueadora Verilog

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 zerar os flip-flops, portanto, toda vez que o relógio marca o transição de 0 para 1 (posedge), verificamos se o reset está ativado (reset síncrono), então continuamos com a lógica normal. Se olharmos de perto, veremos que no caso da lógica combinatória tínhamos “=” para atribuição, e para o bloco sequencial, tínhamos o operador “< =”. Bem, “=” está bloqueando a atribuição e “< =” é uma atribuição sem bloqueio. “=” 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 atribuições sem bloqueio eram sequenciais, enquanto as atribuições de bloqueio eram paralelas. Afinal, você pode fazer atribuições de bloqueio com instruções de atribuição fora dos blocos always, e todos eles são executados em paralelo. Isso é um erro ou o comportamento é diferente dentro de um bloqueio sempre? E, se o comportamento FOR diferente dentro de um bloco always, as atribuições não bloqueadoras podem ser feitas fora de um bloco always?

Resposta

tinha quase certeza de que as atribuições de não bloqueio eram sequenciais, 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 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.

Comentários

  • E as instruções de atribuição? Eles estão apenas em uma classe inteira própria?
  • Sim, as declarações assign ocorrem fora dos blocos always e geralmente são usadas para descrever a combinação (un-latched ) lógica (embora sempre bloqueie, com algumas exceções, descreve a lógica sequencial). AFAIK, assign instruções sempre executam ” em paralelo ” sempre que seu LHS tem uma alteração de valor .
  • Ok … Eu ‘ estou começando a ter a impressão de que Verilog simplesmente não é ‘ o mais linguagem elegantemente desenhada. Vai ser como aprender C.
  • Verilog foi projetado para ” descrever ” hardware que já existe. Usá-lo como uma linguagem para projetar (sintetizar) hardware é um hack.
  • se Verilog ” gosta de aprender C ” é um problema, dê uma olhada em VHDL. Algumas pessoas têm preferências bastante fortes por um ou outro. Para alguns, VHDL é muito prolixo. Para mim, ‘ é muito melhor pensado. (semântica de atribuição de sinal / variável é muito mais clara do que 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.

Resposta

As instruções de atribuição não são “bloqueadoras” ou “não bloqueadoras”, 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 de “bloqueio” e “não bloqueante” existem apenas em blocos always.

Uma atribuição de bloqueio tem efeito imediatamente quando é processada. Uma atribuição não bloqueadora ocorre no final do processamento do “delta de tempo” atual.

Sempre os blocos podem ser usados para modelar lógica combinatória ou sequencial (systemverilog tem always_comb e always_ff para tornar isso explícito). lógica combinatória é geralmente mais eficiente de usar = mas normalmente não importa.

Ao modelar lógica sequencial (por exemplo, sempre @ (posedge clk)), você normalmente usa atribuições não bloqueadoras. Isso permite que você determinar o “estado após a transição do clock” em termos de “o estado antes da transição do clock”.

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

  1. Não acesse um reg que é definido com atribuições de bloqueio dentro de um bloco sempre sequencial de fora do bloco always ao qual ele está atribuído.
  2. Não misture atribuições de bloqueio e não-bloqueio ao mesmo reg.

Quebrar essas regras pode resultar em falhas de síntese e / ou diferenças de comportamento entre simulação e síntese.

Comentários

  • ” ” Não acesse um reg que esteja configurado com atribuições de bloqueio dentro de um bloco sequencial sempre de fora do sempre bloqueie-o é atribuído em. ” ” Você pode explicar isso?
  • Blocos sempre sequenciais diferentes não têm um ordem. Portanto, a leitura de um ” reg ” definido com uma definição de bloqueio em um bloco always de outro bloco always levará a um comportamento imprevisível.
  • E mesmo que pareça funcionar na simulação, uma ferramenta de síntese deve olhar para isso e dizer ” nope “. Eu uso regs locais para esses vars intermediários e certifico-me de que eles sejam sempre atribuídos a cada relógio antes de serem lidos, para que nenhum ‘ armazenamento ‘ está implícito.
  • IIRC, pelo menos no quartus, é apenas considerado um aviso, não um erro.
  • Você não deve usar atribuição não bloqueante na lógica combinacional, pode bloquear a simulação. Para obter mais detalhes, consulte esta resposta: electronics.stackexchange.com/a/506047/238188

Resposta

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

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

De um ponto de vista legalista, tudo funciona muito bem. Você pode, na verdade, considerar o = como uma operação de bloqueio (sequencial no tempo) mesmo dentro de always_comb sequências. No entanto, a distinção entre sequencial no tempo e paralelo não faz absolutamente nenhuma diferença neste caso porque o always_comb bloco é definido para repetir até que a sequência de instruções convirja em um estado estável – que é exatamente o que o circuito de hardware fará (se atender aos requisitos de tempo).

O subconjunto sintetizável de Verilog (e especialmente SystemVerilog) é extremamente simples e fácil de usar – uma vez que você conheça os idiomas necessários. Você só precisa superar o uso inteligente da terminologia associada aos chamados elementos comportamentais na linguagem.

Comentários

  • Em estilos de codificação comportamentais ( 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 designs de componentes comportamentais.
  • Claro que o procedural modo de SystemVerilog, aplicável especialmente a initial instruções dentro de program blocos, usa (sequencial no tempo) atribuição de bloqueio exclusivamente. Isso é útil para o projeto testbench , mas geralmente não para a especificação RTL.

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *