Por que as travas inferidas são ruins?

22

Meu compilador reclama de travas inferidas em meus loops combinatórios ( always @(*), no Verilog). Também me disseram que travas inferidas devem ser preferencialmente evitadas.

O que exatamente há de errado com travas inferidas? Eles certamente tornam os loops combinatórios mais fáceis de escrever.

Randomblue
fonte
Seria bom para incluir um exemplo HDL do que você está fazendo
shuckc
Percebi que essa pergunta foi citada algumas vezes recentemente. Para quem não é um especialista que está por aqui, observe que todas as respostas, além da Oli Glaser, são uma combinação de incorretas e / ou inúteis.
EML
É menos que travas inferidas devam ser evitadas e mais que travas transparentes em geral devam ser evitadas, a menos que você saiba exatamente o que está fazendo (observe que o quartus fornece de forma enganosa a "trava infiltrada" em algumas situações que não envolvem travas transparentes e são perfeitamente seguro).
Peter Green

Respostas:

20

Uma "trava" é diferente de um "flip-flop", pois um FF muda apenas sua saída em resposta a uma borda do relógio. Uma trava pode alterar sua saída em resposta a algo diferente de um relógio. Por exemplo, um SR-Latch possui um conjunto e uma entrada de redefinição e, se um deles estiver ativo, a saída poderá mudar. Onde, como SR-FF, responde apenas a um conjunto ou redefinição quando há também uma borda do relógio.

Em um FPGA, você deseja que sua lógica seja totalmente síncrona. Isso significa que todos os elementos de armazenamento (como os FFs) têm clock de uma única fonte de relógio. Qualquer coisa assíncrona a esse relógio precisa ser tratada com muito cuidado, caso contrário, ocorrerão erros de temporização.

Uma trava é basicamente um elemento de armazenamento assíncrono. Não possui entrada de relógio e, portanto, não pode ser sincronizado com nenhum relógio. Devo observar que existem FFs com redefinições assíncronas e entradas de redefinição, e elas devem ser tratadas com o mesmo cuidado que as travas normais.

Entrar em todos os problemas de tempo que as travas podem causar está muito além do que pode ser abordado aqui, mas deixe-me dar um exemplo:

Digamos que você tenha um SR-Latch e deseje que ele seja definido sempre que um contador de 8 bits atingir um determinado valor. Não sei ao certo qual seria o código Verilog, mas em VHDL o código é: set <= '1' when count = "11010010" else '0'; Esse sinal definido vai para a entrada definida em nosso SR-Latch.

A lógica gerada é puramente combinatória; uma mistura de and-gates, or-gates e inversores (ou LUTs). Mas os caminhos do sinal através dessa lógica combinatória nem sempre são perfeitos e o sinal "definido" pode ter falhas nele. O caminho do sinal através de um grupo específico de portas pode levar mais tempo que outro grupo, fazendo com que a saída definida fique ativa por um breve momento antes que a saída se estabeleça no estado final.

Essa falha de saída pode fazer com que nosso SR-Latch seja configurado, mesmo que não devesse. Se mudarmos de um SR-Latch para um SR-FF, com o mesmo relógio que o contador, o SR-FF aguardará um ciclo de relógio inteiro antes de mudar de estado. Em essência, ele aguardará o sinal definido antes de olhar para ele.

Se os caminhos através da lógica combinatória para o sinal definido forem roteados de maneira diferente (causando atrasos diferentes), o comportamento da falha também mudará. A lógica pode funcionar bem, mas, como você alterou algo totalmente não relacionado, essa lógica é roteada de maneira diferente e, portanto, o bug é exibido. A temperatura e a tensão também alteram o tempo do sinal e, portanto, podem alterar o comportamento da falha.

Essa incerteza no momento é o motivo pelo qual você deve evitar trincos na sua lógica. Os FFs são muito mais seguros de usar. É por isso que o seu compilador está avisando sobre travas, pois é fácil fazer uma trava por engano e você provavelmente não a quer lá de qualquer maneira.

Obviamente, às vezes são necessárias travas. Você só precisa usá-los muito raramente, somente quando absolutamente necessário, e então deve projetar a lógica corretamente, para que não haja falhas possíveis.


fonte
Eu esperaria que se alguém especificasse explicitamente uma trava no verilog ou em outro idioma, e se projetasse um circuito para que funcionasse corretamente com qualquer combinação de atrasos combinatórios que alimentassem a trava (significando que o que quer que estivesse gerando os sinais que seriam combinados para a trava, faria de tal maneira que, mesmo nas combinações de pior caso de caminhos lógicos de atraso zero e caminhos lógicos de atraso máximo, os requisitos de tempo para as travas ainda fossem atendidos), um sintetizador deve gerar um circuito de trabalho onde a trava em si tem um atraso não negativo. Se, no entanto ...
supercat 23/08/12
... usa-se lógica combinatória e feedback sem especificar nós que devam ter um atraso não negativo, quase tudo pode acontecer. Entendo que a lógica síncrona é mais fácil de projetar do que assíncrona, mas muitos dispositivos precisam desligar os relógios quando eles dormem para economizar energia, sem estarem totalmente mortos. Pode ser interessante ter um dispositivo totalmente síncrono, mas que tenha associado a cada pino algumas saídas lógicas para "executar se o pino estiver alto" e "executar se o pino estiver baixo", além da capacidade de gerar um relógio se qualquer pino indicado era necessário.
Supercat 23/08
Essa capacidade mitigaria grande parte da necessidade de lógica assíncrona, pois uma entrada que chegasse enquanto o dispositivo estava em suspensão poderia ligar o oscilador interno e os circuitos apenas o tempo suficiente para que a entrada fosse processada e reconhecida. Esse recurso seria muito mais versátil do que ter um único pino de "ativação", mas os designs de ativação única parecem a norma. Uma abordagem de ativação múltipla, como eu descrevi, consumiria excesso de silício? Eu acho que o requisito de silício seria bem menor comparado com tudo o mais no chip.
Supercat 23/08
13

O que faz uma trava inferida?
Para a lógica combinatória, a saída do circuito é apenas uma função de entrada e não deve conter nenhuma memória ou estado interno (trava).

No Verilog, uma variável manterá seu valor anterior se não lhe for atribuído um valor em um bloco always . Uma trava deve ser criada para armazenar esse valor presente.

Uma instrução if-else incompleta gerará travas. Uma instrução if-else é considerada "incompleta" se o estado de saída não estiver definido para todas as possíveis condições de entrada. O mesmo vale para uma declaração de caso incompleta ou para uma declaração de caso que não possui um item padrão:

Por que as travas inferidas são ruins?
Travas inferidas podem servir como um 'sinal de aviso' de que o design lógico pode não ser implementado conforme planejado. Umainstrução if-else ou case crucialpode estar faltando no design.

Travas podem levar a problemas de tempo e condições de corrida. Eles podem levar ao feedback combinatório - roteamento da saída de volta à entrada - o que pode ser imprevisível.

Para evitar a criação de travas inferidas:

  • Inclua todas as ramificações de uma instrução if ou case
  • Atribua um valor a cada sinal de saída em cada ramificação
  • Use as atribuições padrão no início do procedimento, para que todos os sinais sejam atribuídos.

Algumas partes parafraseadas em "Prototipagem FPGA da Verilog Examples" de P. Chu

dext0rb
fonte
2
"Prototipagem FPGA da Verilog Examples" é um bom livro para aprender o Verilog prático para síntese. Ele tem alguns bons exemplos de designs, de coisas combinatórias básicas a seqüenciais básicas, levando a designs úteis como UART, VGA, processador de núcleo macio (Picoblaze) e até mesmo um jogo de Pong. Ele também abrange testes básicos e simulação. @ Randomblue, você deve pegar uma cópia, se ainda não a tiver. Eu acredito que ele também fez uma versão VHDL também.
Oli Glaser
8

As travas são muito difíceis de usar em FPGAs ou CPLDs, muitas pessoas simplesmente as evitam completamente. Uma das razões é que muitos FPGAs não possuem uma trava embutida, portanto são feitos de portas lógicas - isso pode causar problemas desagradáveis ​​de tempo.
Além disso, você não tem controle sobre atrasos de tempo e condições de corrida ao usar uma trava (a menos que haja um elemento nativo)

Eu desaconselharia o uso de travas, a menos que você não possa prescindir delas (por exemplo, emprestar tempo para atender a uma freqüência de clock máxima necessária) e usar técnicas de codificação para tornar menos provável a ocorrência de travas inferenciais acidentalmente.

Oli Glaser
fonte
6

Projetos lógicos seqüenciais construídos usando lógica combinatória e feedback geralmente assumem uma suposição razoável quando se usa portões físicos: que a saída de um portão não será alterada em resposta a uma mudança na entrada, até algum tempo após a entrada ter realmente mudado. Há algumas ocasiões em que essa suposição pode não se manter ao usar portas reais (por exemplo, se um portão NOR rápido e um inversor rápido forem ambos acionados por um sinal que sobe lentamente de VSS para VDD, e se o inversor alternar a 1,2 volts enquanto o NOR o gate não muda até 1,7 volts, o gate NOR pode ver a saída do inversor baixa antes de ver que o sinal de aumento lento subiu), mas esses problemas geralmente podem ser resolvidos adicionando-se um buffer sempre que uma mudança lenta o sinal é roteado para mais de um destino. Infelizmente,

O problema é que, a menos que seja explicitamente instruído de outra forma, um compilador FPGA pode substituir arbitrariamente um circuito combinatório por um circuito totalmente diferente, com o mesmo comportamento em estado estacionário, mas com um tempo totalmente diferente. Por exemplo, suponha que uma função combinatória complexa F receba seis entradas U a Z. F seja alimentada diretamente no circuito P e (F NAND Z) seja alimentada no circuito Q. O compilador pode perceber que o valor alimentado para Q dependerá apenas de F quando Z é alto e pode calcular uma função F 'que é como F, exceto que Z é considerado alto; Q pode então ser alimentado com (F 'NAND Z) em vez de (F NAND Z). Seria perfeitamente possível que a realização mais eficiente de P tivesse cinco atrasos de porta, mas a realização mais eficiente de Q teria apenas dois. Portanto,

Se um circuito tiver um loop de feedback combinatório, um compilador FPGA precisará adicionar nós de sinal físico que fisicamente terão um atraso positivo (um loop de feedback de atraso zero não pode existir no mundo real), mas não há garantia de que esses nós seriam adicionados nos locais necessários para fazer o circuito se comportar conforme desejado. Também não há garantia de que uma leve alteração no design não faça com que o compilador mude de um posicionamento arbitrário que funciona no mundo real, para um posicionamento arbitrário diferente que falha.

supercat
fonte
0

Detalhes sobre como capturar uma trava no design são explicados brevemente neste link.

https://www.doulos.com/knowhow/fpga/latches/

user3303020
fonte
1
Bem-vindo ao EE.SE! Você pode melhorar sua resposta incluindo alguns detalhes relevantes no link. Isso garante que sua resposta seja de alta qualidade, mesmo que a página original desapareça.
David David