Portal - FPGA para Todos

Memória ROM de 8 nibbles

Memória ROM de 8 nibbles

 

Este artigo descreve o funcionamento de uma memória ROM de 8 nibbles, que só permite a leitura dos dados armazenados. Este projeto é um exemplo VHDL no Quartus® II, retirado do livro "Elementos de Lógica Programável com VHDL e DSP" [1] e detalhado, utilizando as bibliotecas IEEE no VHDL, além de ser implementado no kit de CPLD. A memória ROM implementada aqui é um dispositivo combinacional bastante simples, basicamente uma estrutura de decodificação e multiplexação de dados. A simulação será feita por testbench no ModelSim®-Altera.

Neste projeto será utilizado:

Lógica de Funcionamento

A memória implementada aqui possui três entradas e uma saída: RDn, que é o pino de entrada para habilitação da leitura; ENABLEn, pino de entrada para habilitação de saída; ADDR: barramento de entrada para endereço de três bits; e DADO: barramento de saída de dados de quatro bits. Quando a entrada de leitura (RDn, ativa em nível lógico baixo) está habilitada juntamente da entrada de habilitação (ENABLEn, também ativa em nível lógico baixo), é possível realizar o processo de leitura do dado no endereço selecionado.

O endereço desejado é selecionado através da porta ADDR de três bits. No total, são oito endereços, e cada um aponta para um espaço da memória. Desta forma, se selecionarmos o endereço "001", a memória apresentará na saída o dado armazenado nesse endereço (contanto que os pinos ENABLEn e RDn estejam ativados). A entrada de habilitação, por sua vez, é ativa em nível lógico baixo, e se estiver desativada, a memória não funciona. Assim, para ler um dado, é necessário ativar a memória e também a entrada RDn, para habilitar a leitura. No entanto, estes processos devem ser feitos passo a passo para evitar (convergir transição de sinais); por exemplo, para ler o dado no endereço "000", primeiro deve-se selecionar o endereço, e em seguida ativar a leitura. Somente após conferir as entradas é possível realizar a leitura sem problemas ativando a memória.

A figura 1 ilustra o símbolo gerado pelo Quartus II para o projeto, com as suas entradas e saídas definidas no VHDL. Este bloco pode ser utilizado para a criação de projetos maiores e mais complexos.

 

Figura 1 - Símbolo resultante do VHDL

Um exemplo de sistema que se poderia desenvolver, incorporando um bloco de memória como o proposto aqui, poderia ser uma pequena CPU (unidade central de processamento) para um sistema computacional didático. Além da memória, também são utilizados registradores, ULAs e decodificadores de instruções, que podem ser encontrados descritos em outro artigos (veja "Exemplos Didáticos", no menu do portal).

Projeto em VHDL

O projeto foi modelado em VHDL, e pode ser dividido em quatro partes: declaração de bibliotecas, declaração da entidade, declaração dos tipos e sinais, e lógica de funcionamento.

A primeira parte do código apresenta as bibliotecas e pacotes que serão utilizados durante o programa. Os pacotes são arquivos que contém as declarações de funções e tipos que podem ser utilizados no desenvolvimento do projeto. Uma biblioteca é um conjunto de pacotes. No início de cada programa é preciso dizer quais as bibliotecas e quais os pacotes, dentro das bibliotecas, serão utilizados. Nesse projeto será utilizado a biblioteca padrão IEEE e os pacotes std_logic_1164, que define o tipo std_logic, e numeric_std, que possibilita a realização de algumas opereções matemáticas para o tipo std_logic.

-- bibliotecas IEEE
library ieee;
 use ieee.std_logic_1164.all;
 use ieee.numeric_std.all;

A entidade é onde se declaram as entradas e saídas do projeto. Nesse projeto teremos como entradas: a habilitação do componente, a habilitação de leitura e o endereço de três bits. A saída será um dado de 4 bits, ou seja, um nibble.

-- interface I/O
entity rom_8nibbles is
 port( ENABLEn: in std_logic; -- habilitador ativo em nível lógico baixo
 RDn: in std_logic; -- leitura ativa em nível lógico baixo
 ADDR: in std_logic_vector (2 downto 0); -- endereçamento
 DADO: out std_logic_vector (3 downto 0)); -- saída de dados armazenada
 end rom_8nibbles;

Na sessão "architecture", é declarado um tipo, chamado arranjo, que será um "array" (vetor) de oito dados do tipo std_logic_vector (3 downto 0) que serão referenciados por um número inteiro (no caso, "integer range 0 to 7"). Depois de declarar o tipo, é declarado também uma constante do tipo array, que neste caso são os valores correspondente aos vetores (de x"1" a x"8", em que x indica que o valor atribuido está em hexadecimal). Para cada arranjo, há um endereço específico, e é possível acessar este endereço com o barramento de bits ADDR. Por exemplo; caso queira ler o endereço "010", seleciona-se os bits de entrada em ADDR e a memória efetua o processo de leitura do dado armazenado.

architecture arm of rom_8nibbles is
 type arranjo is array (integer range 0 to 7) of std_logic_vector (3 downto 0); -- função
constant conteudo: arranjo := -- conteudo armazenado na memoria
 (x"1", x"2", x"3", x"4", x"5", x"6", x"7", x"8"); -- endereço 0, 1, 2, 3, 4, 5, 6, 7

Após declarar os dados, é preciso descrever também a leitura do dado. Assim, na sessão "begin", a entrada DADO se relaciona com o respectivo endereço através de "DADO <= conteudo(to_integer(unsigned(ADDR)))", de forma que dado receberá o valor armazenado no endereço ADDR da constante conteúdo. Note que como ADDR é um "std_logic_vector"  e o argumento aceito pela constante é do tipo inteiro, é necessário fazer uma conversão de "std_logic_vector" para inteiro sem sinal. A leitura só ocorre quando ENABLEn e RDn estão em nível lógico baixo. Para o restante das situações, a saída fica em alta impedância, como descreve a sessão "else (others => 'Z')".

begin

 DADO <= conteudo(to_integer(unsigned(ADDR))) when ((ENABLEn = '0') and (RDn = '0'))
-- leitura do dado na ROM
 else (others => 'Z');
 end arm;

Simulação

Neste projeto, utilizamos o testbench para realizar a simulação. Um testbench é uma ferramenta do ModelSim que permite simular projetos através de estapas descritas e pré-definidas em um código, o qual é configurado no software e executado, exibindo as formas de onda como resultado. Observe abaixo o código do testbench para este projeto (você pode criar um com etapas diferentes).

 LIBRARY ieee;
 USE ieee.std_logic_1164.all;
 LIBRARY work;
 entity testbench is
 end entity;

 architecture simulacao of testbench is
 signal ENABLEn, RDn: std_logic;
 signal ADDR: std_logic_vector (2 downto 0);
 signal DADO: std_logic_vector (3 downto 0);

 begin
 UUT: entity work.rom_8nibbles
 port map
 (ENABLEn, RDn, ADDR, DADO);

 SIMULACAO:
process
begin
ENABLEn <= '1';
 RDn <= '1';
 ADDR <= "000";
 wait for 10 us;
 RDn <= '0';
 wait for 10 us;
 ENABLEn <= '0';
 wait for 10 us;
 ENABLEn <= '1';
 ADDR <= "001";
 wait for 10 us;
 ENABLEn <= '0';
 wait for 10 us;
 ENABLEn <= '1';
 wait for 10 us;
 wait;
 end process SIMULACAO;
 end architecture;

O testbench funciona como um código em VHDL que, na simulação, realiza as estapas descritas no processo "SIMULACAO" do VHDL nesta sessão. Analisando o código, podemos verificar as etapas e pausas de tempo com a forma de onda na própria simulação do ModelSim-Altera, como mostra a figura 2. Observe que as etapas descritas na lógica de funcionamento foram seguidas, primeiro selecionando o endereço, e em seguida a leitura, para somente depois habilitarmos a memória.

Figura 2 - Simulação no ModelSim-Altera utilizando Testbench

Estrutura Física

O projeto é composto pelo módulo de CPLD, uma placa de LEDs do tipo catodo comum, uma barra de chaves e uma placa de botões, conectados respectivamente no CON1, CON2 e CON3 do kit, como mostra a figura 3. Lembre-se de que o CPLD usado é o EPM7064, da família MAX7000S.

No projeto, as entradas de endereçamento são pela placa de chaves, e as entradas de habilitação e leitura são implementadas pela placa de botões, tendo a necessidade de manter cada botão apertada para continuar a realizar o processo. A saída de dados é mostrada na placa de LEDs, utilizando quatro dos mesmos, e as funções lógicas pelo kit de CPLD.

Figura 3 - Estrutura física do projeto

Montagem e Roteamento

Fique atento para que o Vcc e o GND dos periféricos fiquem alinhados com o do CPLD. Veja em detalhe a montagem do projeto na figura 4, feita no Fritzing.

Figura 4 - Montagem da periferia no Fritzing

A figura 5 ilustra a pinagem atribuída para o CPLD durante o processo "Pin Planner" no Quartus II, de acordo com a periferia escolhida.

Figura 5 - Pin Planner no Quartus II

Gravação e Teste

Depois de implementar e atribuir os pinos do projeto, faça uma compilação do projeto para gerar o arquivo de gravação, além do programa procurar algum erro ou aviso no mesmo. Para gravar o projeto siga o tutorial do wink na etapa de "Gravação do CPLD" do artigo "Decodificador 3x8".

Lembre-se sempre de gravar o módulo de CPLD separadamente dos periféricos, evitando problemas na pinagem atribuida em projetos anteriores. É importante também sempre lembrar de definir os pinos não utilizados como entradas tri-state.

Para testar o funcionamento desse projeto, monte a periferia indicada na sessão "Montagem e Roteamento" deste artigo e vá alterando o barramento de endereço através das chaves, assim como os botões de leitura e habilitação.

Arquivos do Projeto

Para fazer o download do projeto completo, clique aqui.

O arquivo está no formato ".zip", e inclui os arquivos de projeto do Quartus (".qpf"), de modo VHDL para simulação (".vhd"), de gravação do CPLD (".pof"), de símbolo para usar em projetos mais avançados (".bsf"), entre outros.

Referências

[1] COSTA, Cesar da; MESQUITA, Leonardo; PINHEIRO, Eduardo. Elementos de Lógica Programável com VHDL e DSP: Teoria e Prática. 1. ed. São Paulo: Érica, 2011.

Quem está Online

Temos 104 visitantes e Nenhum membro online

Apoio

Login Form