Como estruturar projetos em FPGA e VHDL - Parte 2

projetos em FPGA e VHDL
Este post faz parte da série Como estruturar projetos em FPGA e VHDL. Leia também os outros posts da série:

Introdução

 

No artigo anterior, eu comentei sobre algumas questões de relógio e temporização. Isso ao mesmo tempo não tem nada a ver com a organização de um projeto em FPGA e, ao mesmo tempo, tem tudo a ver. Nada a ver pois uma árvore de relógio decente faz com que o relógio seja algo a ser rapidamente esquecido. Tudo a ver porque se não fizer direito, a quantidade de problemas é insuportável.

 

Após entender as técnicas de relógio e, principalmente, como trocar de domínio de relógios, é hora de começar a entender melhor como isso influencia nos projetos. Além disso, é importante entender também como organizar os projetos em FPGA em nível de chip, ou seja, entender melhor como será a arquitetura do seu sistema.

 

Porém, antes de entender esse planejamento de chip, é preciso organizar os blocos que organizam tais chips. A isso usa-se o nome de CORE, que nada mais é que um bloco fechado em HDL. Só que para entender isso, eu vou ter que trazer um conceito apócrifo, que é o modelo PC-PO.

 

 

Técnicas de Projeto

 

O Modelo PC-PO

 

O modelo PC-PO foi uma estratégia de projetos defendida pelos professores Luigi Carro e Altamiro Susin na UFRGS em uma época em que sistemas digitais eram coisa de maluco: por um caminhão de TTLs em uma protoboard, no máximo adicionar uma PAL ou um microcontrolador e olhe lá.

 

Esse modelo eles criaram basicamente para ajudar no projeto de ASICs. Infelizmente, após muitas publicações e um livro (Prototipação de Sistemas Digitais, Editora da UFRGS, só achado em sebos), eles não seguiram estudando estas estratégias de projeto. Porém, deixaram essa ideia.

 

O PC-PO significa “parte de controle” e “parte operativa”, respectivamente. Ele define que em circuitos digitais temporizados, uma parte será executora das operações e outra parte será um controle para ordenamento destas operações.

 

Esse conceito é de extrema importância: separar o que está controlando um sistema do que está operando algo ajudará a conceber sistemas cada vez mais complexos sem precisar ficar maluco. Embora existam várias outras metodologias para desenvolver em FPGA (como ESL, Electronic System Level, uso de Java/Python e outras maluquices), essa é bastante simples de entender e por em prática até mesmo por quem está começando.

 

PC-PO aplicado

 

O modelo proposto pelos professores se refere mais a componentes simples. Para tais, a maioria dos sistemas vai possuir:

  • Uma máquina de estados (um contador é uma máquina de estados);
  • Blocos que fazem algo.

 

No caso da Fifo Gray do artigo anterior, a memória é a parte operativa e os contadores são a parte de controle. Porém, um sistema PC-PO não necessariamente é feito em um chip inteiro. Um sistema PC-PO completo pode ser parte de um sistema maior. Veja a figura:

 

 

 

Por exemplo: a fifo que eu mencionei poderia ser parte de um sistema de coleta de dados de um AD. E uma máquina de dados externa poderia ler o estado da fifo e descarregar a mesma apenas quando esta estiver cheia. A fifo, que é composta por um PC-PO, agora é Parte operativa de um sistema maior.

Vejamos mais um caso: vamos pensar em um Framer IP em hardware, algo bem audacioso:

 

 

Desta maneira, o projetista não precisa se preocupar em fazer um grande código de máquina de estados. Basta conceber cada bloco isoladamente, testar e simular. Em seguida, ele reúne tudo e monta o framer.

 

É claro que isto é uma simplificação exagerada do que existe dentro de um framer IP, mas a arquitetura não ficará muito longe disso. E uma coisa muito importante: existem 2 interfaces distintas no bloco acima: uma, de dados, que tem origem naquilo que de útil o sistema deve fazer e outra, com comandos e parâmetros.

 

Os dados, bem, estes tem a mais variada fonte. Porém, os comandos e parâmetros inferem uma necessidade de algo controlando este sistema. Vou deixar esta questão em aberto, pois existe um conceito importante que também está implicito aqui: o Barramento.

 

 

Construção de Cores

 

Um bloco funcional é uma coisa. Um core, no sentido mais amplo, pode ser desde um simples Flip-Flop até mesmo um sistema completo de controle de motor com pwm, inversor e vários sistemas de DSP. Porém, no âmbito deste artigo, vamos entender como um core um periférico que faz alguma coisa.

 

Nenhum projeto de FPGA deveria ser um punhado de máquinas soltas em um único arquivo de HDL: na verdade um projeto se constroi com a interligação dos diversos cores, em uma filosofia parecida com a do modelo PC-PO. Mas para isso dar certo, algumas coisas devem ser bem entendidas.

 

Clocking em Cores

 

Se a recomendação de clock da Parte 1 foi seguida, um core deve ter uma única e exclusiva porta de relógio. No máximo, uma porta secundária de relógio de menor frequência e que obrigatoriamente é síncrona com o clock mestre, ou seja, é o clock mestre dividido por um número inteiro.

 

Toda e qualquer taxa deve vir por enables independente do seu valor.

 

Mapear o Core em Memória

 

Em algum momento, todo o sistema em FPGA encontrará algum microprocessador. E quando encontrar este microprocessador, de alguma forma ele deverá apresentar entradas para receber configuração e saídas de status, bem como portas de entrada e saída de dados.

 

Se formos avaliar por exemplo um FPGA que seja escravo de um microcontrolador, isso poderia ser feito com GPIOs. Porém, nem sempre tais GPIOs terão velocidade ou estão em quantidade suficiente para poder fazer os cores funcionar de maneira apropriada. Para isso, condensa-se tais informações e registros e utiliza-se mecanismos de acesso... E isso é o bom e velho conhecido mapeamento em memória.

 

Tomando como referencia os barramentos mais “clássicos” como o barramento de memórias FLASH, há sempre um endereço, um dado e sinais de controle. Isso será feito para que o sistema de controle acesse o core e o configure de maneira apropriada.

 

Quando eu comecei com FPGA, a forma que eu aprendi a mapear em memória era criar um banco de registradores (não sabe o que é? Google for it!) e ligava os blocos a ele.

 

Algo assim:

 

 

Porém, quando eu usava estes mesmo bloco em outros projetos, eu acabava ligando eles de forma diferente:

 

 

Ao fazer isso, se perdia todo o software, pois o mapa de memória era todo diferente. Além disso, eu tinha que recordar como as coisas estavam ligadas e a produtividade geral graças ao baixo reuso era menor. Ou seja: uma má decisão de construção dos cores me levava a problemas no chip level e comprometiam o projeto inteiro. Então, era preciso amarrar mais um conceito... E, finalmente, chegamos ao ponto em que trabalharemos na organização do chip.

 

 

Chip Level Design (SOC Design)

 

Finalmente, chegamos à organização de um projeto de chip. Veja o exemplo abaixo:

 

 

  • Temos os cores, todos em relógio síncrono
  • O barramento e os cores (Parte operativa)
  • Os mestres (partes de controle)

 

Portanto, uma vez que a construção dos blocos esteja correta, a construção do chip também vai estar. A manutenção isolada em cada bloco é muito pequena. O projeto de chip deve ser como uma brincadeira de lego: basta encaixar as peças umas as outras e pronto: o chip está funcionando.

 

Para esta mágica acontecer, é preciso definir padrões.

 

Barramentos

 

Todo mundo sabe o que é um barramento. Engenheiros conhecem vários exemplos deles. USB, PCI, PCI-E e por aí vai. Porém, a maioria começa um projeto em FPGA sem pensar em como vai ligar as próprias construções. Entra então o problema da falta de uma especificação de barramento.

 

O barramento justamente vai fazer a conexão dos blocos construídos com uma interface padrão, ou seja, o desenvolvedor não precisará ficar remendando suas construções como uma colcha de retalhos toda vez que iniciar um projeto novo. Em outras palavras: o barramento vai padronizar o modo como se mapeia em memória o core.

 

Eu não vou discorrer especificações de barramento, mas hoje em dia, se eu fosse usar um barramento para todos os meus projetos, certamente eu usaria o AXI, da ARM tanto nas versões normal ou Streaming. Ele é completo, sem frescuras e com boa documentação disponível.

 

Uma vez que um barramento tenha sido escolhido, ele vai ser a porta pela qual o controle irá configurar, ler estados e interagir com o core. Todos os blocos em FPGA tem sempre algum tipo de interface padrão para controlá-lo, caso contrário, o bloco acaba tendo uma grande quantidade de fios que, a cada projeto, mudam.

 

Ao adotar um barramento padrão, o core passa a ter uma parte operativa e uma porta para uma parte de controle externa, que seria o barramento, que será sempre ligada da mesma maneira.

 

 

Desta forma, toda vez que um bloco for reutilizado, seus registros ficarão sempre nos mesmos lugares. Talvez o que venha a mudar é um offset no mapa de memória, porém isso nada mais é que um parâmetro.

 

 

Clocking

 

Primeiro ponto é definir o relógio principal e sua fonte.

 

É bom lembrar que cada core deve individualmente respeitar e possuir um único relógio mestre (ou o auxiliar síncrono). Assim, a única tarefa necessária é encontrar um valor de frequência maior que a maior taxa de dados do FPGA. Vale lembrar que isso pode ser obtido através de PLLs, muito comum em qualquer FPGA hoje em dia. Pronto. Nada de grandes elucubrações sobre o relógio: ele é sagrado, mas se respeitado, não é um desafio.

 

Em seguida, conecta-se todos os demais relógios assincronos e planejar as mudanças de domínio de relógio, seja com sincronizadores ou fifos grey.

 

Recursos dedicados: Instanciação x Inferência

 

Mais um conceito importante em FPGA:

 

Instanciação: quando explicitamente se refere a um determinado bloco dedicado do FPGA.

 

Inferência: quando a descrição funcional de determinado hardware induz ao uso de um determinado bloco dedicado do FPGA.

 

Eu não recomendo declarar recursos dedicados dentro de cores por instanciação. Porém, não vejo e até recomendo que se faça a codificação de maneira a “inferir” estes blocos.

 

Por que? Porque um HDL bem escrito para Xilinx pode funcionar muito bem com Altera e vice-versa. Essa flexibilidade só ajuda a empresa em que o desenvolvedor trabalha e permite que se aproveite o melhor destes fabricantes.

 

PLLs, Fifos, e etc que não podem ser instanciados por “inferência” e só podem ser declarados devem ser feitos fora de todos os cores e eu normalmente faço isso no topo do projeto. Assim, fica muito claro quais blocos são blocos da minha biblioteca e quais são do fabricante: numa eventual necessidade de portar o código para outro fabricante, copia-se todo o miolo exceto circuitaria de borda e estes blocos dedicados.

 

Para concluir, as ferramentas de síntese em FPGA possuem “coding patterns” que explicam e auxiliam os desenvolvedores a declarar blocos por inferência.

 

 

Conclusão

 

Todos os conceitos apresentados nestes dois artigos são conceitos um pouco básicos para o bom projeto de sistemas em FPGA. Embora simples, muitos destes conceitos, técnicas ou ideias não estão presentes no dia a dia do aprendizado de lógica programável: assim como foi comigo e muitos conhecidos meus, essas ideias brotaram ou foram adotadas por necessidade: os projetos cresciam e a complexidade não diminuia e, no fim, já tive sistemas insustentáveis que me forçaram a recriar, do zero, algo que deveria estar funcionando.

 

Organizar um projeto em FPGA é simples se as ações necessárias e corretas forem tomadas antes mesmo do projeto começar. Um projeto em FPGA jamais poderá ser visto como sendo um grande macarrão de várias construções lógicas encadeadas como se fosse uma enorme protoboard.

 

Um projeto em FPGA é melhor entendido sobre o modelo de quebra-cabeças em que cada peça é uma entidade completa por si só e tem suas fronteiras bem definidas. Ela encaixa-se às demais peças e isso em conjunto forma o “chip”.

 

Eu espero que os conceitos apresentados aqui ajudem aos iniciantes a entender melhor e estruturar melhor seus projetos em FPGA, para que, depois, não penem dando suporte às suas próprias criações e consigam colocar sistemas gigantescos para rodar, em FPGAs bem utilizados (90% de ocupação, por exemplo), sem grandes dores de cabeça.

Outros artigos da série

<< Como estruturar projetos em FPGA e VHDLOrganize sua Biblioteca em Lógica Programável >>
Este post faz da série Como estruturar projetos em FPGA e VHDL. Leia também os outros posts da série:
NEWSLETTER

Receba os melhores conteúdos sobre sistemas eletrônicos embarcados, dicas, tutoriais e promoções.

Obrigado! Sua inscrição foi um sucesso.

Ops, algo deu errado. Por favor tente novamente.

Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.

Ricardo Tafas
Ricardo F. Tafas Jr é Engenheiro Eletricista pela UFRGS com ênfase em Sistemas Digitais e mestre em Engenharia Elétrica pela PUC com ênfase em Gestão de Sistemas de Telecomunicações. É também escritor e autor do livro Autodesenvolvimento para Desenvolvedores. Possui +10 anos de experiência na gestão de P&D e de times de engenharia e +13 anos no desenvolvimento de sistemas embarcados. Seus maiores interesses são aplicação de RH Estratégico, Gestão de Inovação e Tecnologia Embarcada como diferenciais competitivos e também em Sistemas Digitais de alto desempenho em FPGA. Atualmente, é editor e escreve para o "Repositório” (https://www.repositorio.blog), é membro do editorial do Embarcados (https://www.embarcados.com.br) e é Especialista em Gestão de P&D e Inovação pela Repo Dinâmica - Aceleradora de Produtos.

Deixe um comentário

avatar
 
  Notificações  
Notificar