O que é FPGA?

Em 26 de dezembro de 2015

De algum tempo para cá, muito se ouve falar em FPGA no meio da retrocomputação, principalmente por causa de alguns autores de hardware que vivem nos surpreeendendo com diversas novidades para os videogames e micros de 20-30 anos de idade. Claro que um FPGA não é exclusivo para retrocomputação, mas tem feito um relativo sucesso pela facilidade de uso e principalmente o preço que esses componentes tem aparecido no mercado. Antes de falarmos do FPGA em si, precisamos de uma pequena introdução para podermos entender o funcionamento da coisa.

Provavelmente qualquer pessoa sabe que as máquinas dessa época foram construídas com circuitos integrados digitais, além de algum apoio analógico para geração de som e video. Pois bem, esses CIs digitais, são compostos de portas lógicas que ligadas e agrupadas de determinadas maneiras, desempenham funções específicas. Como exemplo, vou citar o TTL 7432, muito comum nessa época


O 7432 nada mais é do que 4 portas lógicas "OU" dispostas num invólucro de 14 pinos. Nesse caso é bem fácil de notar que as portas não tem ligação entre si, mas vamos ver um exemplo um pouco mais complexo, o TTL 74245


Aqui já bem mais interessante! Temos buffers com porta de controle, além de de duas "E" com inversores em algumas entradas. Traduzindo em miudos, este CI permite a passagem de dados do lado A para o lado B ou do lado B para o lado A, a depender do seu pino de direção DIR. Além disso tem o pino ENABLE, que habilita ou não o seu funcionamento.

Bem, para realmente ser útil para alguma coisa, precisamos de ao menos um punhado de CIs, que combinados, farão algo específico. Por exemplo, eu poderia combinar algumas portas do 7432 com a entrada ENABLE do 74245, fazendo com que determinada situação precisasse ser atendida para que o CI permitisse a passagem dos dados. E assim iríamos colocando mais e mais CIs, até completarmos o circuito.

Mas... e se pudessemos "personalizar" o nosso próprio CI, fazendo a ligação das portas como quisessemos, conseguindo nossa função específica? Ai entra o PLD, abreviação de programmable logic device, ou no português, dispositivo lógico programável. Ele foi bastante utilizado na época e além de simplificar e diminuir o tamanho dos circuitos, ainda permitia um primeiro nível de proteção contra cópia, prática muito comum na época, já que os dados da programação do CI não podiam ser lidos. Como exemplos de PLDs, podemos citar as PALs ou sua versão mais moderna, as GALs.


Com o passar do tempo, a evolução do PLD chegou com o CPLD, o complex programmable logic device ou dispositivo complexo lógico programável, que aumentava a quantidade de portas lógicas internas, conseguindo que circuitos realmente grandes pudessem ser agrupados numa única pastilha. O melhor exemplo que posso citar é o artigo A ULA em CPLD do TK90X, onde conto em forma de diário como foi o desenvolvimento e a série Dissecando a ULA, com vasta explicação sobre o assunto.


Bem, chegamos então ao FPGA, o Field Programmable Gate Array ou em português, Arranjo de Portas Programável em Campo. Enquanto que o CPLD é o "irmão maior" do PLD, não podemos dizer o mesmo do FPGA. Apesar de do ponto de vista prático, um FPGA ser apenas um CPLD "grande", a tecnologia envolvida é muito diferente. Enquanto o CPLD recebe a programação na sua própria pastilha, o FPGA tem uma pequena memória externa com a programação, que é transferida cada vez que o equipamento é ligado. Numa comparação meio extravagante, seria como dizer que um FPGA se comporta como uma RAM, que perde seu conteúdo cada vez que é desligado, e precisa receber os dados novamente quando ligado. O processo é MUITÍSSIMO rápido e não é perceptível, mas acontece.


A organização interna do FPGA também difere um pouco, conforme vemos as imagens ilustrativas abaixo. Os blocos laranja são os de lógica, que são roteados pelos switch boxes em azul.
Warning: imagejpeg(): Unable to open 'cpld-clean_t.jpg' for writing: Permission denied in /home/victortrucco/funcoes.php on line 111

Warning: imagejpeg(): Unable to open 'fpga-clean_t.jpg' for writing: Permission denied in /home/victortrucco/funcoes.php on line 111



Enquanto nos PLDs e CPLDs, os blocos lógicos são agrupados fazendo pequenos conjuntos, no FPGA eles tem formato de matriz bi-dimensional. Na prática isso significa que as ligações no FPGA podem ser mais complexas e mais rápidas que no CPLD, gerando um hardware mais otimizado. E não apenas isso: eu poderia ter um código que teoricamente caberia num CPLD, mas simplesmente não seja possível sintetizá-lo por não existir ligações suficientes entre os diversos blocos. Vale lembrar também que os FPGA mais modernos além da matriz de lógica já contém blocos prontos para RAM e DRAM, USB, Ethernet e diversas facilidades. Consulte sempre o datasheet específico de cada um deles para ver os "extras" e como utilizá-los.

Bem, não quero me prender nos mínimos detalhes de diferenças de funcionamento, então vamos dizer que o FPGA é o "primo" do CPLD e apesar das diferenças internas, ele funciona igual, porém com bastante mais espaço para programação. Para se ter uma idéia de quanto mais espaço estamos falando, citei anteriormente que a ULA coube em um CPLD, mas em FPGA, mesmos os menores, caberia o TK90X TODO, incluindo ai "embutido" o processador Z80, RAM e ROM, incluindo alguma lógica para ler um teclado PS/2 externo e alguma interface de leitura rápida de cartão SD. Na verdade praticamente qualquer máquina dessa época tem alguma versão em FPGA, sejam micros Commodores, Ataris, Sinclairs, TRSs, Apples e até mesmo o curioso CCE MC1000, programado por este que vos escreve.

Um detalhe, que dá um nó na cabeça de muita gente: apesar de usar o termo "programação" algumas vezes no artigo, não é literalmente um programa que roda dentro do FPGA, sendo executado linha a linha, na ordem que foi escrito. Tudo acontece AO MESMO TEMPO em paralelo. Isso quer dizer que você fez a implementação de um CI e precisa de um outro igual, basta instanciar um novo e ambos estarão rodando juntos, ou cinco, ou dez, basta ter espaço na pastilha.

Vi a imagem abaixo outro dia e ilustra EXATAMENTE o que seria um FPGA rodando :D



Depois dessas leves explicações, vamos ao primeiro mito:
Temos micros antigos rodando em FPGA. Isso é uma EMULAÇÃO, certo?

Ah, não poderiam estar mais enganados, vamos analizar... "Emulação", na prática, significa que temos algum tipo de interpretador que traduzirá comandos/funções para permitir a execução de softwares originalmente destinados para a máquina alvo. Por exemplo, um PC rodando Windows ou Linux, convertendo o software que era em cartuchos e dando saída para o video como se fosse um video game Atari. Porém, notem que necessariamente é preciso um processador para isso. No exemplo citado, temos uma máquina X86/X64, traduzindo o que seria do processador 6502. O mesmo acontece com o Raspberri Pi que usa uma CPU ARM para as emulações. Então, fora o caso proposital e absurdo de um autor sintetizar uma CPU para emular outra CPU no mesmo FPGA, ele não será NUNCA uma emulação, mesmo porque o FPGA não roda código, conforme já explicado acima.

O segundo mito:
Ok, não é uma emulação, mas é uma SIMULAÇÃO, certo?

Aqui a resposta é: DEPENDE... Hoje existem vários jeitos de se escrever um projeto para ser sintetizado em um FPGA. Pode ser usado linguagens de alto nivel como VHDL, Verilog, ABEL, CUPL e muitas outras ou do jeito "difícil" que é montar as ligações das portas lógicas. Vamos ver dois casos distintos usando o 74245 que já falamos, onde apesar de eu ter usado o software Quartus para pastilhas da Altera, poderia ter sido o ISE pro Xilinx.

Sintetizando o 74245 por behaviour


Nesta versão escrita em VHDL, fiz um pequeno código que simula o comportamento (behaviour em inglês), do que seria o 74245. Ou seja, aqui nós temos uma SIMULAÇÃO do componente, porque na prática eu não sei como as portas assumiram as posições dentro do FPGA, estou querendo apenas que funcione como um 74245, sem me interessar como.

Tirando a encheção de linguiça das declarações da linguagem, o que realmente interessa são as linhas 25 e 26:

bus_a <= bus_b when dir = '0' and enabled = '0' else ( others => 'Z' ); 
bus_b <= bus_a when dir = '1' and enabled = '0' else ( others => 'Z' ); 


Na primeira, dizemos que se o ENABLE estiver em nível baixo e se o DIR estiver em nível baixo, copiamos a porta B para a porta A. Na segunda, se ENABLE em nível baixo e DIR nível alto, copiamos porta A para porta B. Se alguma das condições não forem atendidas, as portas ficam desconectadas (nível "Z"). E de onde tirei essa informação do funcionamento? Do datasheet do 74245.

Sintetizando o 74245 por portas




Nesta segunda versão, o que fiz foi copiar EXATAMENTE a configuração das portas do 74245. Aqui temos o componente em si, na mesma configuração original, não uma simulação. Logicamente ainda teríamos algumas diferenças como Fan-In e Fan-Out, tempos de propagação e afins, mas pelos meus testes não influenciam na prática o resultado final, levando em conta o universo da retrocomputação.

Pegando agora um exemplo palpável da sintetização da famosíssima CPU Z80, temos o T80 que simula um Z80 por comportamento, enquanto o A-Z80 é o Z80 copiado porta a porta por engenharia reversa com micro-fotografias da pastilha exposta. Qual a diferença entre eles? O T80 difere, mesmo que pouco da CPU original, conforme o texto explicativo do site. Curiosamente inclusive tinha um bug que foi consertado pelo Fabio Belavenuto, durante testes no TBBlue. Já o A-Z80 tem exatamente as mesmas características e bugs que a versão usada durante a captura das imagens. Os dois funcionando em aplicações corriqueiras, não se vêem diferenças groseiras, mas aquele pequeno detalhe ou glitch que só acontece no micro ou videogame rodando em FPGA certamente são desses detalhes das implementações por comportamento.

Mas se a sintetização por portas é bem melhor, por que quase ninguém usa? O primeiro e mais importante, é que nem sempre temos a configuração das portas dos CIs que queremos sintetizar e, mesmo que tenhamos, é um trabalho hérculo desenhar porta a porta. Nos dois exemplos acima, enquanto perdi 40 minutos desenhando as portas da primeira versão, a segunda saiu em 2.

Enfim, a sintetização em FPGA é uma ferramenta poderosíssima e quando usada para retrocomputação pode ser igual à máquina original, bastando apenas conhecimento e sobretudo paciência para fazer as implementações e decifrar as mínimas nuances. Ou seja, não culpem a ferramenta, mas sim o autor! :D

Dúvidas ou sugestões, utilize o espaço abaixo.


Voltar - Home


Comente



COMENTÁRIOS DESABILITADOS NO MOMENTO! RETORNAM EM BREVE
É expressamente proibido a reprodução total ou parcial deste texto sem a minha devida autorização por escrito.