Ahmes – Implementação em FPGA Cyclone IV

Olá, no meu primeiro artigo sobre o Ahmes[1], também publicado no portal Embarcados, nós vimos o modelo de programação da CPU, o código VHDL e a simulação da operação da CPU hipotética no IDE Quartus II da Altera[2]. Neste artigo vamos dar um passo além e demonstrar a implementação real do Ahmes num FPGA.

Apesar de ser possível sintetizar o Ahmes conforme já apresentado e programar um FPGA com o projeto original, decidi reformular algumas partes do Ahmes de forma a melhor aproveitar os recursos do FPGA. Por isso, ao invés de utilizar uma memória descrita totalmente em VHDL, decidi utilizar uma memória RAM disponibilizada como uma MegaFunction[3] da Altera, além disso, foi criada uma porta de saída mapeada no endereço 255 da memória.

As MegaFunctions são designs ou circuitos lógicos (conhecidos por IP de Intellectual Property ou Propriedade Intelectual) previamente testados e disponibilizados pela Altera para uso com os seus componentes. A vantagem de se utilizar uma MegaFunction é que o ambiente Quartus II irá utilizar os blocos de memória RAM internos do FPGA (embedded memory M9K[4] no Cyclone IV) ao invés de elementos lógicos e registradores como no exemplo anterior. Além disso, a utilização de uma memória baseada num IP fornecido pela Altera é garantia de confiabilidade de design e maior flexibilidade, já que tais memórias são totalmente configuráveis e permitem o carregamento prévio do seu conteúdo via arquivos HEX ou MIF e inclusive a inspeção e alteração em tempo real do seu conteúdo!

Para verificação e testes de operação foi utilizado um pequeno kit baseado no modelo Cyclone IV[5] EP4CE6. Ele possui apenas uma porta USB (utilizada para alimentação da placa e comunicação serial através de um chip conversor serial-USB FTDI FT232RL), duas teclas de usuário, oito leds, tecla de configuração, módulo oscilador de 50MHz, memória de configuração EPCS4[6] e o próprio FPGA, um Cyclone IV EP4CE6E22C8 com 6.272 elementos lógicos, 30 blocos M9K (cada um com capacidade de 9.216 bits, totalizando 276.480 bits de memória interna), 15 multiplicadores 18×18 bits e 2 PLLs.

Figura 1 - Kit do FPGA Cyclone IV
Figura 1 – Kit do FPGA Cyclone IV

Alteração da Memória do Ahmes

O processo de substituição da memória RAM anterior, totalmente definida em VHDL, pela nova versão baseada num IP da Altera, implica em inserir um novo componente no projeto.

Antes de mais nada, é importante destacar que o FPGA alvo do presente projeto é o Cyclone IV modelo EP4CE6E22C8, que é o modelo encontrado no kit que foi utilizado.

Observe que estão disponíveis diversos modelos de memórias, tanto RAMs, quanto ROMs, nas mais variadas formas (single-port, dual-port, FIFO, etc) e também registradores de deslocamento. No presente caso, vamos utilizar uma memória síncrona baseada no IP LPM_RAM_DQ.

ahmes_mem1
Figura 2 – Seleção do IP LPM_RAM_DQ

Em seguida, o Quartus II irá carregar o wizard de configuração do IP. Através de diversas telas o usuário será guiado no processo de parametrização e configuração da memória.

Figura 2 - Wizard: seleção da linguagem e nome do modelo a ser criado
Figura 3 – Wizard: seleção da linguagem e nome do modelo a ser criado

Na próxima tela o wizard apresenta os parâmetros básicos de configuração da memória: largura do barramento de dados, número de palavras (posições) da memória e opções de clock. A configuração utilizada no Ahmes é de 256 words de 8 bits, com clock simples. Observe que na parte inferior da janela o wizard indica que será utilizado um módulo M9K (dos 30) de memória embarcada (embedded memory) do FPGA.

Figura 3 - Wizard: parâmetros básicos da memória
Figura 4 – Wizard: parâmetros básicos da memória

Na próxima tela temos mais algumas opções para as portas e sinais de controle da memória. No nosso caso, devemos desativar os registradores da porta de saída “q” conforme mostra a figura 5.

Figura 5 -
Figura 5 – Outras configurações da memória

A tela mostrada na figura 6 permite configurar o comportamento de leitura da memória durante uma escrita. No nosso caso vamos deixar a configuração padrão (o dado lido é o novo dado escrito).

Figura 5 -
Figura 6 – Comportamento na leitura durante escrita

A tela seguinte (figura 7) permite configurar como será o comportamento de inicialização da memória. Para o Ahmes, vamos configurar a memória para ser inicializada a partir do arquivo loop2.mif que faz parte do projeto. Ele contém o código binário de um pequeno programa para piscar os leds conectados a porta de saída do Ahmes.

Outro detalhe importante e que pode ser útil é habilitar a opção “Allow In-System Memory Content Editor to capture and update content independent of the system clock”. Na prática esta opção faz com que o Quartus II utilize um IP de memória dual-port que permite que tanto a CPU Ahmes quanto a interface JTAG acessem o conteúdo da memória! Esta opção é muito interessante para desenvolvimento e pode ser desabilitada posteriormente, já que consome recursos adicionais do FPGA.

Figura 7
Figura 7 – Inicialização da memória

Feito isso, o Quartus II irá gerar os arquivos necessários para utilização do componente no projeto, bastando inserir o símbolo no esquemático do Ahmes.

O conteúdo de inicialização da memória RAM é definido no arquivo loop2.mif, cujo conteúdo pode ser visto através do editor do Quartus II. Na verdade o arquivo mif é um arquivo texto que também pode ser editado através de um editor de texto qualquer.

Figura
Figura 8 – Conteúdo do arquivo loop2.mif

Porta de Saída

Além da alteração na memória, o novo Ahmes também precisa de uma porta de saída para poder comunicar-se com o mundo! Para isso foi criado um pequeno componente para a função de porta de saída de 8 bits (batizado inadequadamente de PIO, mas que não tem uma função input real). Este componente utiliza um código VHDL muito simples e que é mostrado abaixo:

LIBRARY ieee ;
USE ieee.std_logic_1164.all ;
USE ieee.std_logic_unsigned.all ;

ENTITY pio IS
 PORT
 (
   address_bus : IN INTEGER RANGE 0 TO 255;
   data_in : IN INTEGER RANGE 0 TO 255;
   out_port : OUT INTEGER RANGE 0 TO 255;
   mem_write : IN std_logic
 );
END pio;

ARCHITECTURE porta_io OF pio IS
BEGIN
   process (mem_write)
   BEGIN
     IF (RISING_EDGE(MEM_WRITE)) THEN
       IF (ADDRESS_BUS=255) THEN
         out_port <= DATA_IN;
       END IF;
     END IF;
   end process;
END porta_io;

Este código basicamente define um registrador de 8 bits que é escrito quando a CPU faz uma operação de escrita no endereço 255 da memória. Note que tanto o registrador quanto o conteúdo da memória RAM são escritos na mesma operação, no entanto, a leitura do endereço 255 retorna o conteúdo da RAM e não deste registrador.

Assignment

O último passo para podermos fazer a síntese final do Ahmes é definir quais os pinos do FPGA receberão os sinais de clock, reset e a porta de saída. Este processo é conhecido como assignment e é iniciado através da opção “Assignment Editor” no menu Assignments do Quartus II. O assignment dos pinos do Ahmes deve ser feito conforme mostra a figura 9.

Figura 8 - Pin Assignment no Ahmes
Figura 9 – Pin Assignment no Ahmes

A aparência final do esquemático de alto nível do Ahmes deve ser a da figura 10. Note que foi ncluída uma porta inversora na entrada de clock da RAM. Isto faz com que as operações de escrita e leitura da memória sejam sempre disparadas na borda de descida do sinal de clock (lembre-se de que o Ahmes coloca endereços e dados na borda de subida do clock). A razão para a inclusão da porta foi apenas garantir que os endereços e dados na entrada da memória estejam estáveis no momento em que são amostrados pela mesma.

Figura
Figura 10 – Novo esquemático do Ahmes

Síntese e Programação

Após o processo de síntese do projeto, o sumário contendo um relatório de recursos utilizados no FPGA é apresentado:

Figura
Figura 11 – Sumário da síntese do projeto

Veja que o Ahmes completo, com uma porta de saída e 256 bytes de RAM ocupou apenas 459 elementos dos 6.272 do nosso FPGA e apenas 2.048 dos 276.480 bits disponíveis! Isso significa que há muito espaço sobrando para uma CPU muito mais complexa e com muito mais memória interna! Além disso, o FPGA que utilizamos é o menor disponível na linha Cyclone IV, que inclui modelos com até 115 mil elementos lógicos e quase 4Megabits de memória embarcada! Outros FPGAs da própria Altera e de outros fabricantes podem atingir capacidades ainda maiores!

Uma vez sintetizado o projeto, é hora de descarregar o mesmo no FPGA. O resultado final da síntese do projeto é um arquivo .sof que contém a configuração do FPGA e o conteúdo de inicialização da memória. Para transferir este arquivo para o FPGA basta utilizar a ferramenta de programação do Quartus II:

Figura
Figura 12 – O programador do Quartus II

Uma vez transferido o arquivo de configuração, o FPGA inicia imediatamente a operação e o Ahmes ganha “vida”! Bem vindo ao mundo real Ahmes!

Um detalhe importante é que este processo apenas configura o FPGA através da interface JTAG (utilizando o USB Blaster), mas lembre-se de que o nosso FPGA (assim como a maioria deles) é baseado em tecnologia RAM, ou seja, são voláteis e perdem a sua configuração com a ausência de tensão de alimentação. É por este motivo que existe a memória de configuração (a EPCS4 no nosso caso): ela é uma FLASH serial que armazena um (ou mais) arquivos de configuração e é utilizada pelo FPGA no instante do boot, ou seja, a configuração armazenada na mesma é carregada automaticamente pelo FPGA na partida do sistema.

O processo para gravação da memória de configuração é diferente daquele demonstrado acima, ao invés de utilizar diretamente o arquivo sof, precisaremos gerar um arquivo jic para configuração indireta via JTAG. Na prática o processo implica em programar o FPGA como uma bridge que irá transferir os dados da JTAG diretamente para a memória de configuração.

Para gerar este arquivo jic é necessário converter o arquivo de programação (menu File>Convert programming files…) conforme ilustra a figura 13.

É necessário selecionar o tipo de arquivo de programação como sendo JTAG indirect configuration file (jic), selecionar o modelo da memória de configuração (EPCS4) e nos arquivos de entrada selecionar o modelo de flash loader (EP4CE6) e o arquivo SOF do projeto (ahmes.sof). Em seguida basta clicar em Generate para que o arquivo jic seja gerado.

Figura
Figura 13 – Conversão de arquivos de programação

Uma vez gerado o arquivo jic, abra o programador do Quartus II, remova o arquivo de gravação anterior e adicione o arquivo jic recém gerado. Em seguida selecione a opção “Program/Configure” e clique em Start para iniciar o processo de gravação da memória. Observe que este tempo é substancialmente maior que a programação do FPGA.

Figura
Figura 14 – Programador configurado para gravar a memória de configuração EPCS4

Uma vez concluída a gravação, o Ahmes iniciará a operação assim que a placa for alimentada!

Antes de concluirmos este artigo, vejamos uma outra funcionalidade bastante interessante e extremamente útil: a visualização em tempo real do conteúdo da memória embutida no FPGA. Esta funcionalidade está disponível graças a configuração do componente IP da memória com a opção para acesso via In-System Memory Content Editor).

Para acessar essa ferramenta basta clicar na opção de mesmo nome dentro do menu “Tools” do Quartus II. Uma janela semelhante a mostrada na figura 15 será exibida. Uma vez que a ferramenta tenha estabelecido conexão com o FPGA, basta selecionar a instância desejada (0 no caso) e clicar no botão de leitura da memória (ou pressionar a tecla F5) para que a ferramenta seja atualizada com o conteúdo atual da memória do Ahmes! É possível também alterar o conteúdo da memória (F7) e ativar a visualização em tempo real (F6).

Figura
Figura 15 – Editor de memória do FPGA em tempo real

Observação: o leitor atento irá perceber que a tela da figura 15 apresenta o FPGA conectado como sendo um EP3C10/5, ou seja, um Cyclone III. Este fato também chamou a atenção do autor do artigo, que resolveu investigar (considerando que poderia ser o caso de um chip remarcado), mas ao consultar o Handbook da linha Cyclone IV[5], ficou claro que o ID apresentado 0x020F1 é o do EP4CE6 realmente. Portanto deve tratar-se apenas de um erro da ferramenta do editor de memória!

Conclusão

Este artigo demonstrou que a implementação do Ahmes não somente funciona na teoria (simulação) mas também na prática.

De quebra o artigo também apresentou alguns detalhes adicionais sobre FPGAs, VHDL e a ferramenta Quartus II (versão 9.1sp2).

No mais, esperamos que o leitor divirta-se tanto quanto o autor nas aventuras com estes fabulosos processadores sintéticos!

Todos os arquivos do projeto estão disponíveis na minha conta do GitHub.

Referências

[1] – Ahmes uma CPU simples em VHDL

[2] – Altera

[3] – Altera MegaFunctions

[4] –  Memórias embarcadas M9K

[5] – Handbook dos componentes Cyclone IV

[6] – Datasheet das memórias de configuração EPCS da Altera

Leave a Reply