Teach lesson
Lógica digital na DE1-SoC com VHDL (3/6): memória — flip-flops e registradores
Use processos VHDL sincronizados para construir um flip-flop D e um registrador de 8 bits e comprovar o comportamento de memória no hardware real.
New to LabsLand? Create your teacher account
Learning Outcomes
Explicar por que a lógica sequencial precisa de memória, ao contrário da lógica combinacional.
Descrever o flip-flop D como amostragem e retenção na borda de clock, com reset síncrono.
Construir um registrador de carga paralela de 8 bits com flip-flops que compartilham clock e reset.
Usar atribuição de sinal em processos VHDL sincronizados e reconhecer entradas KEY ativas em nível baixo.
Student activity preview
Activity Content
Preview only. In a class session, students can fill in responses and submit their work to the teacher.
Por que os circuitos precisam de memória
10 min
Todos os projetos anteriores eram combinacionais: os LEDs dependiam apenas das posições das chaves naquele instante. Ao mudar uma chave, a saída mudava assim que o sinal atravessava as portas. Um circuito combinacional não tem estado: não sabe quais eram as entradas há um momento e não consegue guardar nada.
Mas sistemas úteis precisam de memória. Um contador precisa conhecer seu valor atual para gerar o seguinte. Uma CPU precisa manter operandos e resultados entre instruções. Um semáforo precisa saber qual cor está acesa para decidir a próxima. Portas isoladas refletem apenas as entradas presentes.
Lógica sequencial é a lógica que se lembra. Sua saída depende das entradas atuais e também de um estado armazenado. O flip-flop guarda um bit de estado, e o clock informa quando todos os flip-flops devem se atualizar.
A DE1-SoC fornece um clock livre de 50 MHz chamado CLOCK_50, que sobe e desce 50.000.000 de vezes por segundo. A partir desta lição, os projetos sequenciais precisam declará-lo como entrada. O modelo padrão blink.vhd não inclui clock; você deverá adicionar CLOCK_50 : in std_logic à entidade. Esquecê-lo é um dos erros mais comuns em projetos sequenciais.
Qual destes circuitos é sequencial, isto é, sua saída pode depender do passado?
Por que um flip-flop ou registrador precisa de CLOCK_50 : in std_logic, e o que costuma acontecer se essa entrada for omitida? Responda em uma ou duas frases.
Flip-flop D: amostrar e manter na borda de clock
11 min
Um flip-flop D é o elemento de memória mais simples. Ele tem entrada de dados D, entrada de clock e saída Q. Sua regra é:
> Em cada borda de subida do clock, Q captura o valor de D e o mantém até a próxima borda de subida.
Entre bordas, as mudanças de D não alteram Q. Isso é amostragem e retenção: o flip-flop amostra D quando o clock passa de 0 para 1 e mantém a amostra estável. Assim, Q pode continuar valendo 1 mesmo depois de D voltar a 0.
Amostragem e retenção: Q só se atualiza em cada borda de subida de CLOCK_50, copiando o valor de D naquele instante e mantendo-o até a borda seguinte.
Duas ideias novas em VHDL.
Primeiro, o processo sincronizado. O comportamento sensível à borda é descrito com process(CLOCK_50) e if rising_edge(CLOCK_50) then. As atribuições dentro do processo indicam o que cada flip-flop captura na borda; não são instruções executadas continuamente.
Segundo, a atribuição de sinal <=. Dentro de um processo sincronizado, Q <= SW(0); descreve a atualização do flip-flop na borda. Variáveis VHDL usam := e mudam imediatamente dentro do processo. Regra deste curso: use sinais e <= para valores armazenados, como flip-flops, registradores, contadores e estados de FSM.
Reset síncrono. Um reset síncrono é verificado *dentro* do bloco do clock e só tem efeito em uma borda:
process(CLOCK_50)
begin
if rising_edge(CLOCK_50) then
if KEY(0) = '0' then Q <= TODO_RESET_VALUE;
else Q <= TODO_D_INPUT;
end if;
end if;
end process;
KEY é ativo em nível baixo: o botão lê 0 quando pressionado. Portanto, KEY(0) = '0' é verdadeiro enquanto o reset está pressionado.
Por que <= é a forma correta para atualizar a saída de um flip-flop neste processo, e por que vários registradores precisam amostrar juntos na mesma borda de clock?
Se D pulsar para 1 apenas entre duas bordas de subida e voltar a 0 antes da borda seguinte, Q chega a valer 1? Explique com a regra de amostragem e retenção.
Exercício 2-A — flip-flop D com reset
12 min
Monte um flip-flop D na placa real. Use SW(0)=D, KEY(0)=reset ativo em nível baixo, LEDR(0)=Q e LEDR(1)=not Q.
Leia antes de executar. A 50 MHz, Q amostra D 50.000.000 de vezes por segundo, muito mais rápido do que o olho ou a câmera. Por isso, ao mover SW(0), LEDR(0) parece acompanhar imediatamente. Este exercício demonstra visualmente o reset, não a retenção:
- Com SW(0) para cima, LEDR(0) acende e LEDR(1) apaga.
- Mantendo KEY(0) pressionado, LEDR(0) apaga mesmo com SW(0) para cima: o reset vence os dados.
- Ao soltar KEY(0), LEDR(0) volta a acompanhar SW(0).
-- Código inicial do estudante: preencha as linhas TODO antes de sintetizar.
-- Lição 3 - Exercício 2-A: flip-flop D.
-- SW(0)=D, KEY(0)=reset ativo em nível baixo, LEDR(0)=Q, LEDR(1)=not Q.
library ieee;
use ieee.std_logic_1164.all;
entity blink is
port (
CLOCK_50 : in std_logic;
KEY : in std_logic_vector(3 downto 0);
SW : in std_logic_vector(9 downto 0);
LEDR : out std_logic_vector(9 downto 0)
);
end entity blink;
architecture rtl of blink is
signal Q : std_logic := '0';
begin
process(CLOCK_50)
begin
if rising_edge(CLOCK_50) then
if KEY(0) = '0' then Q <= TODO_RESET_VALUE;
else Q <= TODO_D_INPUT;
end if;
end if;
end process;
LEDR(0) <= TODO_Q_OUTPUT;
LEDR(1) <= TODO_NOT_Q_OUTPUT;
LEDR(9 downto 2) <= (others => '0');
end architecture rtl;Abra o laboratório VHDL da DE1-SoC. O editor mostra
blink.vhd.Substitua todo o arquivo pelo código acima, complete cada TODO, mantenha a entidade
blinke confirme a entradaCLOCK_50 : in std_logic.Clique em Synthesize (Sintetizar). Feche ou pule o tour se ele cobrir o botão. Aguarde de 1 a 3 minutos e corrija qualquer erro até obter sucesso com 0 erros.
Clique em Upload to FPGA (Enviar para a FPGA) e aguarde a câmera.
Coloque
SW(0)para cima e confirmeLEDR(0)aceso eLEDR(1)apagado.Com
SW(0)ainda para cima, pressione e mantenhaKEY(0):LEDR(0)deve apagar. Solte o botão e confirme que o LED volta a acender.
Defina SW(0) e KEY(0) em cada linha e registre LEDR(0)=Q e LEDR(1)=not Q na câmera. KEY é ativo em nível baixo: pressionado=0, solto=1.
| SW(0) (D) | KEY(0) (0=pressionado, 1=solto) | LEDR(0) = Q | LEDR(1) = not Q |
|---|---|---|---|
Qual é a diferença entre este flip-flop e um fio direto de SW(0) para LEDR(0)? Responda em termos de memória.
Este projeto usa reset síncrono. Indique a linha que realiza o reset e explique o que “síncrono” significa quanto ao momento em que ele tem efeito.
Por que LEDR(1) sempre mostra o oposto de LEDR(0)?
O Exercício 2-A armazena D, mas a câmera só permite ver o reset. Use a frequência de 50 MHz para explicar por que a retenção fica invisível e o reset é claramente observável.
Exercício 2-B — registrador de carga paralela de 8 bits
12 min
Um registrador reúne N flip-flops D lado a lado, com o mesmo clock e reset. Um registrador de 8 bits armazena 8 bits. A carga paralela copia os oito bits de entrada ao mesmo tempo em uma borda de clock.
O controle de carga torna a memória visível. O registrador só captura quando solicitado; você pode mudar as chaves e o valor armazenado permanece. Use SW(7 downto 0)=dados, KEY(0)=reset e KEY(1)=carga, ambos ativos em nível baixo.
Para carregar, pressione e solte KEY(1). O código amostra o nível do botão em cada borda de clock, o que é suficiente para este exercício.
-- Código inicial do estudante: preencha as linhas TODO antes de sintetizar.
-- Lição 3 - Exercício 2-B: registrador de carga paralela de 8 bits.
-- SW(7 downto 0)=dados, KEY(0)=reset, KEY(1)=carga. KEY é ativo em nível baixo.
library ieee;
use ieee.std_logic_1164.all;
entity blink is
port (
CLOCK_50 : in std_logic;
KEY : in std_logic_vector(3 downto 0);
SW : in std_logic_vector(9 downto 0);
LEDR : out std_logic_vector(9 downto 0)
);
end entity blink;
architecture rtl of blink is
signal Q : std_logic_vector(7 downto 0) := (others => '0');
begin
process(CLOCK_50)
begin
if rising_edge(CLOCK_50) then
if KEY(0) = '0' then
Q <= TODO_RESET_VECTOR;
elsif KEY(1) = '0' then
Q <= TODO_LOAD_VALUE;
end if; -- caso contrário, Q mantém o valor anterior
end if;
end process;
LEDR(7 downto 0) <= TODO_REGISTER_OUTPUT;
LEDR(9 downto 8) <= (others => '0');
end architecture rtl;Substitua todo o conteúdo de
blink.vhdpelo registrador acima. Complete os TODOs e mantenhaCLOCK_50 : in std_logic.Clique em Synthesize, aguarde o sucesso e depois em Upload to FPGA.
Defina
SW(7 downto 0)=10101010. Os LEDs ainda não mostrarão esse valor porque nada foi carregado.Carregue: pressione e solte
KEY(1). AgoraLEDR(7 downto 0)mostra10101010.Observe a memória: mude as chaves para
01010101sem pressionarKEY(1). Os LEDs permanecem em10101010.Atualize: pressione e solte
KEY(1)novamente. Os LEDs mudam para01010101.Reinicie: pressione e solte
KEY(0). Os oito LEDs apagam, independentemente das chaves.
Execute a sequência e registre LEDR(7 downto 0) em cada etapa. Na linha em que as chaves mudam sem carga, o valor armazenado deve permanecer igual ao anterior.
| Etapa | SW(7 downto 0) definido como | Ação em KEY | LEDR(7 downto 0) observado |
|---|---|---|---|
Envie sua evidência. Faça uma captura que comprove a retenção: LEDR(7 downto 0) deve mostrar 10101010 enquanto as chaves mostram um padrão diferente, como 01010101, sem uma nova pressão em KEY(1).
Você mudou as chaves, mas os LEDs não mudaram. Explique por quê usando as palavras “armazenar” e “carregar”.
Se reset (KEY(0)) e carga (KEY(1)) estiverem pressionados na mesma borda de clock, qual valor o registrador assumirá e por quê? Indique a linha que decide essa prioridade.
Qual é a finalidade prática de um registrador de carga paralela em uma CPU? Dê um exemplo concreto do que ele pode armazenar.
O que você construiu e os dois estilos de reset
8 min
Você construiu os fundamentos da memória digital: o flip-flop D, que guarda um bit, e o registrador, que reúne vários flip-flops carregados em paralelo. Usou um processo com rising_edge(CLOCK_50), atribuições de sinal <= e entradas KEY ativas em nível baixo.
Os projetos desta lição usam reset síncrono, verificado dentro do processo do clock. Nas lições seguintes, você também encontrará reset assíncrono, escrito com process(..., KEY) e uma verificação de KEY(0) antes da borda. Ele força um estado seguro sem esperar pelo clock lento.
Qual sequência corresponde ao fluxo usado nos dois exercícios?
Em três ou quatro frases, explique como o Exercício 2-B comprovou a memória, por que o Exercício 2-A só permitiu observar o reset e cite um momento em que a polaridade ativa em nível baixo de KEY foi importante.