Até agora, temos um processador de 8 bits, com 11 instruções, endereçamento de 512 posições de memória de instruções e 512 posições de memória de dados. Vamos utilizá-lo no projeto de um contador que deverá:
Ter um botão de entrada para incrementar a contagem;
Ter um botão de entrada para reiniciar a contagem;
Utilizar as chaves para configurar o limite de contagem;
Mostrar o valor da contagem nos displays de sete segmentos;
Armazenar as variáveis do programa na memória RAM.
Independente da necessidade de utilização, o nosso projeto terá:
Memória ROM, para as instruções, de 512 posições, nos endereços de 0 a 511;
Memória RAM de 64 posições, para os dados, nos endereços de 0 a 63;
Seis posições de E/S para a escrita nos displays de sete segmentos;
Uma posição de E/S para a leitura das chaves SW0 até SW7;
Duas posições de E/S para a leitura de SW8 e SW9;
Cinco posições de E/S para a leitura de FPGA_RESET e KEY0 até KEY3;
Três posições de E/S para a escrita dos LEDs:
Uma para o intervalo de LEDR0 até LEDR7;
Uma para a escrita no LEDR8;
Uma para a escrita no LEDR9;
O esboço inicial do nosso mapa de memória terá os seguintes blocos de 64 posições:
RAM: da posição 0 até a posição 63;
RAM (expansão): reservado da posição 64 até a posição 127;
E/S para escrita: da posição 256 até a posição 319;
E/S para leitura: da posição 320 até a posição 383;
Como o espaço de endereçamento é de 512 posições, e temos blocos de 64 posições, podemos fazer um decodificador de 3 entradas (os bits mais significativos do endereçamento) e 8 saídas (uma para ativar cada bloco de 64 posições).
Utilizando o nosso processador, mostrado abaixo, devemos conectar e endereçar os periféricos listados - mostrados nos desenhos a seguir.
O esboço abaixo será o ponto de partida para a implementação.
A memória RAM ocupa o intervalo de endereços entre 0 e 63.
Ligando os endereços mais significativos (A8, A7 e A6) do barramento de endereços ao decodificador, teremos os sinais de ativação para oito blocos de 64 endereços cada.
A RAM será alocada no primeiro bloco desse decodificador e a faixa de endereços de A0 até A5 será ligada diretamente a ela. Além disso, precisaremos dos sinais que habilitam a escrita ou a leitura da RAM e os barramentos de dados de leitura e escrita.
A figura abaixo, mostra as conexões para esse primeiro periférico.
Vamos implementá-lo em VHDL e testaremos o seu funcionamento junto com a implementação dos LEDs.
Os LEDs estão alocados na faixa de endereços para E/S de escrita (entre 256 e 319). Nesta mesma faixa estão os displays de sete segmentos.
Teremos três endereços, um para um conjunto de oito LEDs (LEDR0 até LEDR7) e outros dois: um para o LEDR8 e outro para o LEDR9. De maneira arbitrária, vamos definir os seguintes endereços:
Endereço 256: 8 LEDs (LEDR0 até 7)
Endereço 257: LEDR8;
Endereço 258: LEDR9.
Para isso, podemos utilizar um novo decodificador de 3 para 8 conectado às linhas de endereços de mais baixa ordem (A0, A1 e A2). A ativação de cada conjunto de LEDs será feita através da ligação de portas AND, conforme mostrado abaixo.
Para o ativar o conjunto de 8 LEDs, no endereço 256, teremos uma porta AND com três entradas:
A saída do decodificador de blocos S4 (endereços entre 256 e 319);
O sinal de habilita escrita (WR);
A saída do decodificador de endereços S0.
Para o ativar o LEDR8, no endereço 257, teremos uma porta AND com três entradas:
A saída do decodificador de blocos S4 (endereços entre 256 e 319);
O sinal de habilita escrita (WR);
A saída do decodificador de endereços S1.
Para o ativar o LEDR9, no endereço 258, teremos uma porta AND com três entradas:
A saída do decodificador de blocos S4 (endereços entre 256 e 319);
O sinal de habilita escrita (WR);
A saída do decodificador de endereços S2.
Vamos implementá-lo em VHDL e testar o seu funcionamento e o funcionamento da RAM. Para tanto, podemos utilizar um programa similar ao mostrado abaixo. Lembre que os valores dos argumentos estão em decimal e precisam ser convertidos para hexadeximal.
Linha | Instrução | Observação |
---|---|---|
0 | LDI $1 | Carrega o acumulador com o valor 1 |
1 | STA @0 | Armazena o valor do acumulador na posição zero da memória (MEM[0]) |
2 | SOMA @0 | Soma o valor atual do acumulador com o conteúdo de MEM[0] |
3 | STA @1 | Armazena o valor do acumulador em MEM[1] |
4 | LDA @0 | Carrega o acumulador com o valor de MEM[0] |
5 | STA @257 | Armazena 1 no LEDR8 |
6 | STA @258 | Armazena 1 no LEDR9 |
7 | LDI $85 | Carrega o acumulador |
8 | STA @256 | Armazena 85 em LEDR0 até LEDR7 |
9 | LDI $170 | Carrega o acumulador |
10 | STA @256 | Armazena 170 em LEDR0 até LEDR7 |
11 | JMP @11 | Fim. Deve ficar neste laço |
O caractere arroba (@) indica um endereço de memória (RAM ou ROM) enquanto que o caractere cifrão ($) indica um valor constante (imediato).
Programa, igual ao acima, para ser copiado e utilizado na ROM, com os devidos ajustes nos endereçamentos.
Esta Atividade deverá ser entregue através do Blackboard!