Como as instruções "sempre" da Verilog são implementadas no hardware?
A alwaysdeclaração Verilog , a saber
executa o block of codequando conditionestá satisfeito. Como esse alwaysbloco é implementado no hardware?
Eu acho que muito depende do que o block of codeé ..
E se a condição é posedge xou apenasx
@ Justin: Vamos supor que não há posedge.
Primeiro, observe que nem todos os designs da Verilog são sintetizáveis. Normalmente, apenas um subconjunto muito específico de construções pode ser usado em um design que deve ser realizado em hardware.
Uma restrição importante que aparece é que todas as regvariáveis ​​podem ser atribuídas apenas em no máximo uma alwaysinstrução. Em outras palavras, regs têm afinidade com alwaysblocos.
Os seguintes tipos de alwaysblocos geralmente podem ser usados.
No primeiro caso, *indica que o bloco deve ser executado sempre que qualquer sinal usado no bloco for alterado ou, equivalentemente, que o bloco deve ser executado continuamente. Portanto, regs que têm afinidade com alwaysblocos combinacionais são implementados como sinais computados de outros sinais usando lógica combinacional, ou seja, portas.
Os registradores que têm afinidade com os alwaysblocos deste último tipo, por outro lado, são saídas de flip-flops D que são marcados com freqüência na borda ascendente de clk(borda descendente, se negedgeusada). As entradas para os flip-flops são, novamente, computadas com lógica combinacional de outros sinais.
Considere o seguinte exemplo, um tanto artificial.
Aqui, out_nestá associado ao primeiro alwaysbloco, outao segundo. out_nserá implementado com um único portão NOT que será acionado out_ne acionado out(observe que é uma lógica combinacional pura). Por outro lado, outserá conduzido por um flip-flop com clock de clk. A entrada para o flip-flop será novamente calculada por um gate NOT out(que é acionado pelo flip-flop acima mencionado). A otimização dos sintetizadores combinará os dois portões NOT e usará um gate NOT e um flip-flop.
Dependendo do hardware que você tem disponível, outros tipos de construções podem ser usados. Por exemplo, se os flip-flops tiverem redefinições assíncronas, a construção a seguir também será sintetizada.
Obrigado. Quanto a isso *, pensei que indicava que o bloco deveria ser executado sempre que qualquer sinal no bloco fosse alterado (em oposição ao design ).
@ Randomblue, você está certo, eu vou corrigir a resposta. Observe, no entanto, que os dois têm comportamento equivalente.
Verdade; justo!
Um alwaysbloco é comumente usado para descrever um flip-flop, uma trava ou um multiplexador. O código seria implementado com um flip-flop, uma trava ou um multiplexador.
Em um FPGA, um flip-flop e uma trava geralmente são apenas duas configurações diferentes de um dispositivo de registro de uso geral. Um multiplexador seria construído a partir de um ou mais elementos lógicos de uso geral (LUTs).
Em geral, existem duas maneiras de desenvolver o design com o Verilog:
Visualize a lógica que você deseja em termos de portas e registros, e descubra como descrevê-la no Verilog. Os manuais de síntese dos fornecedores de FPGA ou de ferramentas de síntese fornecem informações detalhadas sobre as estruturas mais comuns com as quais você pode querer trabalhar.
Escreva o Verilog e não se preocupe com a aparência do hardware subjacente. No entanto, mesmo se você fizer isso, ainda precisará saber o que é e o que não é sintetizável. Então, novamente, você examinará o padrão fornecido pelo fornecedor da ferramenta e o adaptará ao seu aplicativo.
A resposta de Avakar é muito melhor para sua pergunta, mas isso estimulou uma discussão interessante sobre as diferenças entre Xilinx e Altera, para que não a exclua.
"flip-flop e trava são geralmente apenas duas configurações diferentes" São elas? Eu esperaria que as travas fossem implementadas com as LUTs (com cuidado se as LUTs não estiverem livres de falhas).
@avakar, eu sei que em todos os FPGAs Xilinx (ou pelo menos todos remotamente recentes) as travas usam o mesmo hardware que um flip-flop, diferindo apenas por um único bit no fluxo de bits de configuração. Não tenho certeza sobre outras marcas.
— 9119 Kevin Kapcart
Hmm. Alguns projetos antigos da Altera tinham caminhos de feedback que permitiam que o LUT fosse usado para implementar travas. Parece que o roteamento principal pode ser necessário para implementar travas nos novos designs. Isso não é surpreendente, pois no design moderno de RTL trancas reais (em vez de chinelos) raramente são desejadas.
@avakar, eu estou mais familiarizado com o Xilinx, onde o dispositivo de registro pode ser configurado como um flip-flop ou uma trava. Se isso não for possível na Altera ou em algum outro fornecedor, isso tornaria o conselho geral "não projetar com travas" ainda mais forte.
@ KevinCathcart e Photon: Entendo, não estou familiarizado com o Xilinx, apenas com a série Altera Cyclone, que não possui um circuito de trava dedicado.
— Avakar 9/04/12
Como já foi dito, nem todos os blocos são sempre sintetizáveis. Existem também alguns blocos que as ferramentas de síntese aceitarão, mas que produzirão resultados diferentes do que um simulador produzirá.
Primeiro da lista de sensibilidade. A regra usual é que ele deve conter apenas construções de detecção de borda (e geralmente há uma seleção limitada de combinações possíveis) ou deve conter (possivelmente através do uso de * ou always_comb do systemverilog) todos os sinais usados ​​como entrada no bloco. Chamamos o primeiro de bloco combinatório e o último de seqüencial ou bloco. Normalmente, se você incluir apenas um subconjunto de entradas em ferramentas de síntese de blocos combinatórios, apenas o ignorará e agirá como se a lista completa tivesse sido especificada (criando incompatibilidades de simulação / síntese)
Segundo bloqueio versus tarefas noblock. Em um bloco combinatório, a diferença não importa muito, mas em um bloco seqüencial, importa muito.
Em um bloco seqüencial, as atribuições de não bloqueio modelam um registro de maneira bastante direta, enquanto as variáveis ​​do modelo de designações de bloqueio (que podem ou não implicar registros, dependendo da ordem de configuração e leitura). Como regra, um conjunto de "reg" que usa atribuições de bloqueio em um bloco seqüencial deve ser lido apenas no mesmo bloco e as declarações de bloqueio e não-bloqueio não devem ser misturadas no mesmo "reg".
A mistura de atribuições de bloqueio e não bloqueio ao mesmo item provavelmente causará falhas na síntese. Fazer uma avaliação de bloqueio em um bloco e lê-lo em outro provavelmente causará incompatibilidades de simulação / síntese (e possivelmente até incompatíveis entre diferentes execuções de simulação).
Agora temos as regras básicas fora do caminho, podemos considerar como o compilador transforma o código em lógica.
O primeiro passo é desenrolar todos os loops. Isso significa que os loops devem ter uma contagem máxima de iterações que pode ser determinada no momento da síntese ou você receberá uma falha de síntese.
Em seguida, a ferramenta pode analisar o fluxo de controle do bloco e transformá-lo em um fluxo de dados. Cada variável se torna um ou mais sinais. Cada instrução if ou construção semelhante se torna um ou mais multiplexadores, selecionando qual conjunto de resultados será realmente usado.
A ferramenta provavelmente tentará aplicar algumas otimizações.
No quartus, você pode ver os resultados desse processo após a construção do seu projeto, acessando "ferramentas-> netlist visualers-> rtl viewer".
Depois de gerar essa representação estrutural em termos de elementos lógicos abstratos, a ferramenta passará a mapear esses elementos abstratos para os recursos que o chip realmente possui.