Projeto de console dedicado para o Kit de desenvolvimento DE1-SoC
Nos últimos anos, os jogos digitais emergiram como uma forma de entretenimento profundamente influente e culturalmente significativa. Desde os primórdios dos jogos de computador e consoles de videogame até a era contemporânea dos jogos móveis e realidade virtual, a indústria de jogos digitais tem evoluído constantemente. Contudo, é importante o papel dos jogos digitais clássicos, que representam os pilares fundamentais da indústria, transcendendo fronteiras geográficas e geracionais.
Esses clássicos não apenas resistiram ao teste do tempo, mas também continuam a ser celebrados como marcos históricos que ajudaram a moldar o meio dos jogos digitais como o conhecemos hoje. Um desses emblemáticos passatempos é o conhecido Jogo Da Velha ou Tic-Tac-Toe que, apesar da sua origem remontar há mais de 3.500 anos no antigo Egito e da sua dinâmica simples, é um dos jogos mais populares do mundo.
Neste contexto, o presente projeto objetiva o desenvolvimento de um console que implemente uma versão do clássico Jogo Da Velha em uma plataforma de desenvolvimento de hardware. O Kit de desenvolvimento DE1-SoC foi selecionado para a execução do sistema. As soluções, softwares e dispositivos utilizados no desenvolvimento serão abordados nas seções subsequentes.
A solução deve atender às condições e aos requisitos predeterminados, de modo que o jogo deve:- Ser executado em uma interface em modo texto, que possa ser visualizada via terminal;
- Permitir a interação de dois jogadores;
- Captar a posição de marcação da jogada no tabuleiro, assim como a confirmação da ação, por meio de um mouse conectado a uma das portas USB da placa;
- Utilizar os botões e chaves disponíveis na placa para o controle do fluxo do jogo.
- Ter seu código escrito em linguagem C;
- Utilizar exclusivamente os componentes disponíveis na placa DE1-SoC.
- Brenda Barbosa
- Camila Queiroz
- Maike de Oliveira
É uma linguagem de programação de propósito geral que combina abstrações e controles de baixo nível sobre o hardware resultando em ganho de eficiência. O software criado em 1970 por Dennis Ritchie é estreitamente associada ao sistema operacional UNIX, uma vez que as versões desse sistema foram escritas em linguagem C. Além disso, a sintaxe simples e a alta portabilidade desta linguagem entre dispositivos contribui para seu amplo uso em sistemas embarcados de recursos limitados.
O GNU Compiler Collection GCC (Coleção de Compiladores GNU), ou GCC, é um conjunto de compiladores de código aberto desenvolvido pelo Projeto GNU que oferecem suporte a uma gama de linguagens de programação, incluindo C, C++, Fortran, Ada e Go. Esta ferramenta otimiza a compilação, ou seja a produção de código de máquina, nas várias linguagens e arquiteturas de processadores suportadas.
O Visual Studio Code, ou VS Code, é um editor de texto gratuito com suporte a várias linguagens de programação, incluindo Python, Java, C, C++ e JavaScript. A ferramenta desenvolvida pela Microsoft dispõe de diversos recursos de depuração, destaque de erros, sugestões, personalização dentre outros para auxiliar a codificação. Desse modo, o editor foi um dos ambientes utilizados no desenvolvimento do código fonte do jogo.
Também, o editor de texto simples Nano, na versão 2.2.6, presente no Linux embarcado do Kit de desenvolvimento DE1-SoC foi utilizado para codificação da solução. O Nano é um software leve e que oferece uma interface de linha de comando intuitiva, tornando-o ideal para rápida edição de arquivos, scripts e outros documentos de texto.
Nesta seção, exploraremos as principais características do Kit de desenvolvimento DE1-SoC.Equipado com processador, USB, memória DDR3, Ethernet e uma gama de periféricos, o kit de desenvolvimento DE1-SoC (Figura 1) integra no mesmo Cyclone® V, sistema em chip (SoC), um hard processor system (HPS) a uma FPGA (Field Programmable Gate Arrays). Este design permite uma grande flexibilidade da placa nas mais variadas aplicações. Para o acesso ao sistema operacional Linux embarcado na placa, o protocolo de rede SSH (Secure Shell) foi utilizado, estabelecendo uma conexão criptografada para comunicação entre a placa e computador host.
A comunicação bidirecional entre a o HPS e a FPGA se dá por meio das FPGA bridges presentes no dispositivo. Assim, no sentido HPS-FPGA, todos os dispositivos de entrada e saída (E/S) conectados à FPGA são acessíveis ao processador através do mapeamento de memória. As informações sobre o endereçamento dos periféricos estão disponíveis na documentação da placa (FPGAcademy.org).
Como indicado na seção anterior, o kit de desenvolvimento DE1-SoC possui diversos periféricos integrados. Para este projeto, os componentes selecionados foram os botões do tipo push e as portas USB host, ambos destacados na figura 3. Associado a estes dispositivos, utilizou-se também um mouse USB.
A placa utilizada disponibiliza para o usuário quatro botões do tipo push (integrados à FPGA), os quais possuem três registradores com funções diversificadas. São eles o registrador de dados, o registrador maskinterrupt e o registrador edgecapture, todos ilustrados na figura 4.
O registrador de dados é utilizado para identificar quais botões estão pressionados em um determinado instante. Quando um botão é pressionado, seu bit correspondente no registrador é setado com o valor 1. Quando liberado, o bit é setado para 0.
Por sua vez, o edgecapture é utilizado para identificar se um botão foi pressionado desde a última checagem (mesmo que tenha sido liberado). Quando um botão é pressionado, seu bit correspondente no registrador é setado para 1. O valor permanece até que o bit seja limpo (escrever explicitamente o valor 1).
Por fim, o registrador interruptmask é utilizado para manipular as interrupções enviadas ao processador ARM por meio dos botões. Para habilitar as interrupções para um determinado botão, basta setar para 1 no registrador o bit correspondente ao botão.
Na placa DE1-SoC, os conectores USB estão ligados a um HUB controlador que se comunica diretamente com o HPS. Assim, o sistema operacional instalado e em execução na processador ARM da placa é quem gerencia as portas. Esta organização facilita o desenvolvimento e utilização das mesmas. Neste projeto, utilizou-se um mouse (figura 5) conectado à porta USB host da placa.
O produto final integra os módulos de pooling dos pushbuttons e do mouse USB com a lógica do jogo da velha implementada a fim de criar um aplicação que atenda aos requisitos propostos. A aplicação desenvolvida está esquematizada na figura 6.
A fim de maximizar a eficiência da CPU e reduzir o tempo de ociosidade aguardando eventos dos dispositivos E/S, os blocos apresentados foram divididos em threads. Chamados por Tanenbaum (2016) de miniprocessos, as threads compartilham um conjunto de recursos, tal como o espaço de endereçamento, de maneira que possam trabalhar juntos intimamente para desempenhar alguma tarefa, precisamente a interação desejada entre os módulos. As threads implementadas e suas respectivas funções estão listadas abaixo:
- thread de pooling dos pushbuttons: responsável pelo pooling dos botões, bem como a conversão dos dados dos eventos;
- thread de interface de jogadas: responsável pelo pooling do mouse, conversão dos dados dos eventos e display do tabuleiro;
- thread do jogo da velha: responsável pelo controle e display do menu e execução da lógica das partidas.
lwhps2fpga
(Lightweight HPS-to-FPGA Bridge) a qual encarrega-se da conexão entre o FPGA e o HPS da placa. As portas E/S mapeadas nesta ponte podem ser acessadas por meio do endereço base (0xFF200000) somado ao offset da porta (para a porta KEY, offset = 0x00000050). Entretanto, para acessar os valores das portas mapeadas, faz-se necessária a virtualização destes endereços físicos.
A memória virtual é uma técnica utilizada para gerenciamento de memória nos computadores. Nela, cada programa possui seu próprio espaço de endereçamento o qual é mapeado na memória física. Quando o programa referencia uma parte do espaço de endereçamento que está na memória física, o hardware (MMU - memory management unit) encarrega-se de realizar rapidamente o mapeamento (tradução) (TANENBAUM, 2016). Este processo está esquematizado na figura 8.
Para realizar o mapeamento do endereço físico da porta KEY, foram utilizadas as funções mmap()
e unmap()
e o arquivo /dev/mem
(arquivo do Linux que contém um espelho da memória do computador). A partir do endereço virtual gerado, pode-se acessar o registrador edgecapture.
/dev/input
.
No kit de desenvolvimento, o arquivo correspondente aos eventos do mouse USB usado encontram-se no caminho /dev/input/event0
. Este arquivo contém o instante do evento, seu tipo, código e valor. Este padrão de registro de eventos é definido pela interface Input, documentada na Linux Kernel Organization (https://kernel.org/doc/html/latest/input/input.html#event-interface), e apresentado na Figura 9. A struct em linguagem C foi aplicada na decodificação dos eventos do mouse. As informações neste arquivo são sobrescritas a cada novo evento, não acumulando um histórico.
Para a leitura do arquivo event0 em binário, utilizou-se as funções fopen()
e fread()
da biblioteca stdio.
- Eventos de clique são registrados quando algum dos botões do mouse é pressionado ou liberado e retornam 1 ou 0, respectivamente, no campo de valor. Um evento de clique tem valor
type
igual a 2 e valor docode
correspondente ao botão pressionado. - Eventos de movimentação, ocorrem quando há o deslocamento do mouse sobre alguma superfície, retornando, então, um código correspondente ao eixo de movimentação, o sentido -esquerda, direita, cima, baixo - e o módulo correspondente ao deslocamento relativo do mouse. A figura 10 ilustra o funcionamento do mouse com relação a eventos de deslocamento, sendo a seta o sentido do movimento e as variáveis
REL_X
eREL_Y
a velocidade, positiva ou negativa, nos eixos X e Y, respectivamente. Por exemplo, ao movimentar o mouse da direita para a esquerda, obtem-se uma struct correspondente a um evento com tipo igual a 2, indicando o movimento do dispositivo, código igual 0 para o eixo X e valor negativo para o sentido do deslocamento. Tais dados compõem o deslocamento relativo do mouse capturado pelo seu sensor óptico mediante o feixe de luz emitido pelo LED embutido no mouse.
Adotou-se o valor mínimo de velocidade igual a 3, a fim de controlar a sensibilidade do mouse e melhorar a experiência do usuário. Além disso, um contador, incrementado em 1 a cada evento lido e que retorna os dados do evento quando a contagem chega a 7, foi usado para solucionar o problema observado de replicação de eventos por um curto período de tempo.
O jogo da velha consiste em dois jogadores que, de forma alternada, desenham símbolos ('x' ou 'o') em uma matriz 3x3. Durante a partida, um quadrante ocupado não pode ser selecionado. Vence o jogo o player que conseguir formar primeiro uma linha - seja na horizontal, vertical ou diagonal - com o seu símbolo. Caso todas as casas tenham sido preenchidas sem que nenhum jogador forme uma linha, o jogo finaliza em empate ('velha' ).
A seleção de um espaço vazio no tabuleiro, bem como a confirmação da jogada, dá-se por meio do mouse USB conectado ao kit de desenvolvimento. O usuário pode navegar pelos espaços do tabuleiro por meio da movimentação do mouse nas direções horizontal ou vertical, como ilustrado pelas figuras 11, 12 e 13. Ao chegar no quadrante em que deseja inserir o seu símbolo, o jogador pode confirmar a sua jogada por meio do botão esquerdo do mouse.
Independente do modo de jogo selecionado pelo usuário, a execução de uma partida possui um fluxo básico. A partida iniciada permanece em execução até que uma solicitação de encerramento seja realizada ou uma vitória ou empate seja detectada. Ao longo do processo, o fluxo realiza ações de exibição do tabuleiro, registro de jogadas e verificações. A diferença entre os fluxos de partida dos modos dual player e single player, esquematizados nas figuras 15 e 16, respectivamente, é que o último, ao identificar a vez do computador, realiza uma jogada aleatória gerada.
Na tela de menu principal (figura 17), o usuário visualiza o título do jogo e as escolhas disponíveis do jogo: partida dual player, partida single player e sair do jogo.
Com a seleção de um modo de jogo, o tabuleiro é exibido na tela (figura 18) e é dado início à partida. Para o modo dual player, o retângulo ciano descreve a posição em que está o cursor do mouse e o clique confirma a seleção do quadrante na vez de cada jogador (figura 19).Para o modo single player (figura 20), o jogador jogará com o símbolo círculo e o computador com 'x'. Assim, o computador inicia a partida e, logo após, é a vez do jogador, representado pelo retângulo de cor ciano.
No caso de finalização de uma partida (figura 21 e 22), a mesma é finalizada imediatamente e o jogo retorna ao menu principal. Quando acionado no menu principal o jogo é encerrado.
Caso um dos jogadores ganhe (figura 23), será exibido o jogador que ganhou e, após 5 segundos, o jogador será redirecionado ao menu principal.
Caso ocorra um empate (figura 24), será exibida por 5 segundo uma mensagem avisando que houve um empate e, depois, o jogador será redirecionado para o menu principal.Os testes realizados para garantir o correto funcionamento do jogo são apresentados abaixo.
- Iniciar: Transição do menu para a tela da partida a partir do acionamento das KEY1 OU KEY2
- Movimentação durante a partida: Seleção de Quadrante após o primeiro jogador
- Confirmação de jogada com Símbolo X. Click do mouse para confirmação da jogada com símbolo X no quadrante selecionado do tabuleiro.
- Confirmação de jogada com Símbolo 0. Click do mouse para confirmação da jogada com símbolo 0 no quadrante selecionado do tabuleiro
- Vitória na Vertical: Conjunto de 3 símbolos iguais na vertical.
- Vitória na Horizontal: Conjunto de 3 símbolos iguais na horizontal.
- Vitória na Diagonal: Conjunto de 3 símbolos iguais na diagonal.
- Empate: deu Velha ou Draw. Nenhum dos jogadores completa uma trilha de símbolos iguais.
- Interrupção do Jogo durante a partida pelo acionamento da KEY0
Além de compreender os princípio básicos da arquitetura da plataforma DE1-SoC, este projeto proporcionou o aprofundamento e prática em uma distribuição Linux embarcada e dos conceitos de interação entre hardware e software.
Como melhoramento, sugere-se a adição do algoritmo minimax no modo de jogo single player, a fim de tornar as jogadas do computador inteligentes e gerar desafios para os usuários.
- Possuir conexão com internet;
- Possuir o compilador gcc;
- Possuir o git instalado;
- Estar utilizando uma placa de desenvolvimento FPGA DE1-SoC;
- Possuir um mouse conectado a placa;
Caso todos os requisitos anteriores sejam satisfeitos basta seguir o passo a passo
Abra o terminal do seu dispositivo e execute o seguinte comandogit clone https://github.com/brendabo1/Sistema-Digital-TicTacToe.git
cd source/
make all
sudo ./tic-tac-toe
Intel® FPGA University Program DE1-SoC Computer Manual. https://ftp.intel.com/Public/Pub/fpgaup/pub/Intel_Material/18.1/Computer_Systems/DE1-SoC/DE1-SoC_Computer_ARM.pdf. Acesso em: 22 abril. 2024.
Intel® FPGA University Program DE1-SoC Computer System with ARM* Cortex* A9. Disponível em: https://fpgacademy.org/courses.html. Acesso em: 24 abril. 2024.
GCC online documentation - GNU Project. Disponível em: https://gcc.gnu.org/onlinedocs/. Acesso em: 7 maio. 2024.
Linux Input Subsystem userspace API — The Linux Kernel documentation. Disponível em: https://www.kernel.org/doc/html/latest/input/input_uapi.html. Acesso em: 7 maio. 2024.
MARTINS, Luiz. Apostila de Linguagem C (Conceitos Básicos), Virtual Books. Disponível em: https://www.facom.ufu.br/~gustavo/ED1/Apostila_Linguagem_C.pdf. Acesso em: 22 abril. 2024.
TANENBAUM, A. S.; BOS, Herbert. Sistemas operacionais modernos. 4. ed. São Paulo: Pearson Education do Brasil, 2016.
Terasic Techologies Inc. DE1-Soc User Manual. Disponível em: https://www.terasic.com.tw/cgi-bin/page/archive.pl?Language=English&No=836&PartNo=4. Acesso em: 20 abril. 2024.
The Linux Kernel documentation — The Linux Kernel documentation. Disponível em: https://www.kernel.org/doc/html/latest/. Acesso em: 18 abril. 2024.
Universal Serial Bus. Disponível em: https://www.gta.ufrj.br/grad/01_1/usb/usb.htm#%C2%A7%201.1%20%E2%80%93%20Objetivos%20de%20desenvolvimento%20do%20USB. Acesso em: 8 maio. 2024.