Gerar exemplo de debouncer de declaração
A instrução generate em VHDL pode duplicar automaticamente um bloco de código para encerramentos com sinais, processos e instâncias idênticos. É um loop for para a região de arquitetura que pode criar processos encadeados ou instâncias de módulo.
Ao contrário de um loop for regular, que só pode existir em um processo ou subprograma, a instrução generate é colocada diretamente na região de arquitetura do arquivo VHDL. Quando usado em conjunto com genéricos, torna-se uma ferramenta poderosa para projetar módulos VHDL personalizáveis que permitem a reutilização em projetos.
Gerar sintaxe de instrução
A sintaxe do comando generate é a seguinte:
[label :] for <constant_name> in <range> generate
[declarations_local_to_each_loop_iteration]
[begin]
<processes_and_instantiations>
end generate [label];
As partes entre colchetes são opcionais. Assim, você pode omitir a região declarativa e o
begin
palavra-chave se você não quiser declarar nenhum objeto local. O to
ou downto
. Debouncer de switch de um bit
Antes de começarmos com a instrução generate, apresentarei um módulo simples que usaremos como exemplo ao longo deste artigo. É um debouncer capaz de depurar uma única entrada de switch.
Para torná-lo utilizável para qualquer velocidade de clock, adicionei uma entrada genérica chamada timeout_cycles . Essa constante especifica quantos ciclos de clock o tempo limite será depois que a entrada do switch for alterada. O debouncer ignorará qualquer alteração adicional no valor do switch durante o período de tempo limite.
A lista abaixo mostra a entidade do debouncer módulo. Há um interruptor saltitante entrada, e depois há o switch_debounced limpo resultado.
entity debouncer is generic ( timeout_cycles : positive ); port ( clk : in std_logic; rst : in std_logic; switch : in std_logic; switch_debounced : out std_logic ); end debouncer;
O módulo debouncer conta com um contador inteiro para atingir o período de tempo limite. O comprimento do contador sinal segue a constante genérica. É isso que a duração do tempo limite especificada durante a instanciação faz.
Porque precisamos ler o valor do switch_debounced output internamente, eu declarei um shadow signal chamado debounced , que usaremos em seu lugar. Essa é uma solução mais limpa do que a outra opção, que é definir
inout
modo em switch_debounce na entidade. Por fim, implementamos o comportamento de debounce em um único processo, conforme mostrado no código abaixo.
architecture rtl of debouncer is signal debounced : std_logic; signal counter : integer range 0 to timeout_cycles - 1; begin -- Copy internal signal to output switch_debounced <= debounced; DEBOUNCE_PROC : process(clk) begin if rising_edge(clk) then if rst = '1' then counter <= 0; debounced <= switch; else if counter < timeout_cycles - 1 then counter <= counter + 1; elsif switch /= debounced then counter <= 0; debounced <= switch; end if; end if; end if; end process; end architecture;
A forma de onda abaixo mostra uma simulação do debounce módulo no ModelSim. Podemos ver que o switch_debounced a saída segue o switch entrada, mas ignora o comportamento de salto imediato após a primeira mudança - ele debounce o sinal.
Use o formulário abaixo para baixar o código VHDL deste artigo. Ao inserir seu endereço de e-mail, você receberá um arquivo Zip contendo todo o projeto ModelSim com testbenches e um script de execução rápida. Você receberá atualizações futuras do VHDLwhiz e poderá cancelar a assinatura a qualquer momento.
Gerar loop for com instanciações
Para fazer um debouncer para um array de switches, usaremos uma instrução generate para criar várias instâncias do nosso módulo debouncer de um bit.
A lista abaixo mostra a entidade do nosso novo módulo debouncer de vetor ou array. É semelhante ao debouncer de um bit, mas há uma entrada genérica adicional:switch_count . Ele especifica quantas instâncias do módulo debouncer devem ser criadas. Deve haver um para cada switch.
Além disso, renomeei a entrada e a saída do switch para as versões plurais da palavra, e agora elas são vetores em vez de bits únicos.
entity debouncer_gen_inst is generic ( switch_count : positive; timeout_cycles : positive ); port ( clk : in std_logic; rst : in std_logic; switches : in std_logic_vector(switch_count - 1 downto 0); switches_debounced : out std_logic_vector(switch_count - 1 downto 0) ); end debouncer_gen_inst;
Na arquitetura, é hora de usar a instrução generate. Funciona como um loop for regular, apenas com a palavra “generate” substituindo a palavra “loop”. Mas, ao contrário de um loop for regular, ele pode conter instanciações de módulo.
O loop for é executado em tempo de compilação e gera uma instância do módulo debouncer para cada iteração. Mas como a constante “i” será diferente para cada iteração, podemos usá-la para mapear as entradas e saídas dos debouncers para bits individuais nos vetores de switch, conforme mostrado abaixo.
architecture rtl of debouncer_gen_inst is begin MY_GEN : for i in 0 to switch_count - 1 generate DEBOUNCER : entity work.debouncer(rtl) generic map ( timeout_cycles => timeout_cycles ) port map ( clk => clk, rst => rst, switch => switches(i), switch_debounced => switches_debounced(i) ); end generate; end architecture;
Observe que é opcional rotular a instrução generate, mas pode ser sensato fazê-lo. O rótulo aparece na hierarquia do simulador e no log de síntese, facilitando a identificação da instância específica durante a depuração.
A forma de onda abaixo mostra uma simulação do vetor debouncer. Podemos ver que o rótulo “MY_GEN” reaparece aqui, com índices adicionados para cada uma das oito instâncias do debouncer.
Este testbench altera apenas a entrada do switch número 3, é isso que você vê na forma de onda e por isso expandi apenas o grupo MY_GEN(3).
Você pode executar este exemplo rapidamente em seu computador se tiver o ModelSim instalado. Use o formulário abaixo para baixar o código fonte e o projeto ModelSim!
Gerar for loop contendo processos
No último exemplo deste artigo, usaremos uma instrução de geração para fazer uma série de processos idênticos. Em vez de criar instâncias do módulo debouncer de um bit, retirei o código VHDL dele. A entidade é a mesma do exemplo anterior, assim como o comportamento, mas a implementação é diferente.
Podemos ver que movi o processo DEBOUNCE_PROC dentro da instrução generate e alterei um pouco no código abaixo. Desta vez estou declarando dois sinais locais dentro do comando generate:debounced e contador .
Cada iteração do loop for criará uma cópia adicional dos sinais e do processo. O uso desses nomes de sinal dentro do processo fará referência àqueles com escopo definido para o gabinete dessa iteração de loop específica.
Por fim, estou atribuindo o debounced
std_logic
sinal para o bit correto do switches_debounced saída do módulo usando uma instrução concorrente acima do processo. architecture rtl of debouncer_gen_proc is begin MY_GEN : for i in 0 to switch_count - 1 generate signal debounced : std_logic; signal counter : integer range 0 to timeout_cycles - 1; begin switches_debounced(i) <= debounced; DEBOUNCE_PROC : process(clk) begin if rising_edge(clk) then if rst = '1' then counter <= 0; debounced <= switches(i); else if counter < timeout_cycles - 1 then counter <= counter + 1; elsif switches(i) /= debounced then counter <= 0; debounced <= switches(i); end if; end if; end if; end process; end generate; end architecture;
Eu omiti a forma de onda de simulação porque ela parece exatamente a mesma do exemplo anterior usando instanciação de módulo. O comportamento é idêntico.
Você pode baixar todo o código usando o formulário abaixo. Ao inserir seu endereço de e-mail, você se inscreve nas atualizações do VHDLwhiz. Mas não se preocupe, há um link de cancelamento de inscrição em todos os e-mails que eu envio.
Deixe um comentário abaixo se você tiver outro aplicativo útil para gerar declarações para compartilhar! ?
VHDL