Breakout em Assembly 8086
Esta página trata de um jogo de breakout produzido em puro assembly com uso, apenas, da arquitetura de 16 bits. O que significa utilizar apenas os registradores e instruções de 16 bits do processador 8086. Esse jogo funciona independente de sistema operacional. Dado que, dá instruções diretamente ao BIOS do computador. Veja abaixo uma captura de tela do jogo em funcionamento com uso de um emulador de computador, o QEMU:
Download
Downloads
Pendrive IMG: | breakout-asm16-pendrive.img |
Diskette IMG: | breakout-asm16-diskette.img |
GitHub: | https://github.com/italoherbert/breakout-asm16 |
Como Rodar?
Para jogar, basta baixar e gravar a imagem "breakout-asm16-pendrive.img" em um pendrive ou HD, e dar o boot no computador pelo dispositivo onde a imagem foi gravada. A versão "breakout-asm16-diskette.img" é análoga a versão pendrive. Dado que, basta gravar em um diskette e dar o boot por ele.
Entenda que a imagem de pendrive e a de diskette, são conjuntos de zeros e uns que serão gravados, ocupando o setor de boot mestre (O MBR), e mais alguns setores do dispositivo. Logo, para gravar, utilize um utilitário como, por exemplo, o "dd" do linux ou semelhante para windows.
Rodando com emulador de computador
Para executar, por exemplo, a imagem de pendrive pelo qemu, basta executar, sem risco de perda de dados, o seguinte comando:
qemu-system-x86_64 -m 4096 breakout-asm16-pendrive.img
Como Jogar?
-
Para jogar, basta utilizar as setas (traz e frente) do teclado para movimentar a raquete e rebater a bolinha com o objetivo de destruir os quadradinhos retangulares.
-
Use o enter para pausar e o ESC para reiniciar o jogo.
-
O ângulo do trajeto da bolinha em linha reta pode ser alterado se a bolinha for rebatida mais à esquerda ou mais à direita da raquete!
-
Você perde se a bolinha bater na parte de baixo (ao lado da raquete)!
Como o jogo foi implementado?
O nasm foi utilizado como assembler para montar o código objeto do software.
Suporte à instruções de 32 bits
Para ser possível utilizar números de 32 bits de tipo inteiro e até de ponto flutuante, foi necessário implementar instruções que tratassem dados armazenados em dois registradores de 16 bits para formar um número de 32 bits.
Também foram implementadas funções de deslocamento de bits para dados de 32 bits, armazenados em dois registradores de 16 bits.
Sem unidade de ponto flutuante
O processador 8086 não dispõe de unidade de ponto flutuante. Logo, tem suporte apenas à instruções envolvendo representações de números inteiros em registradores de 16 bits. Dado isto, foi necessário implementar o padrão de representação de números em ponto flutuante de precisão simples: O IEEE754.
Foi necessário desenvolver a representação de sinal, expoente e mantissa em dois registradores de 16 bits cada, para compor um número de 32 bits. 1 bit para o sinal, 8 bits para o expoente e os demais 23 bits para a mantissa. Os operadores matemáticos básicos para números de ponto flutuante representados nesse formato também foram implementados. Isto é, soma, subtração, multiplicação e divisão.
As funções matemáticas de 32 bits
Foram implementadas as funções básicas de operação com números de 32 bits, armazenados em duas unidades de 16 bits. Tais funções são: soma, subtração, multiplicação, divisão e de deslocamento de bits.
Foram implementadas também, as funções matemáticas de arredondamento, truncamento, potência, raiz quadrada, e funções trigonométricas. Todas essas funções têm suporte aos números de ponto flutuante representados conforme descrito na seção anterior.
As funções de potência têm suporte a números positivos, negativos, de ponto flutuante com expoentes que também podem ser números positivos, negativos ou de ponto flutuante. O mesmo para a função de raiz quadrada e as trigonométricas. As de arredondamento e truncamento, convertem um número de ponto flutuante em número inteiro de 32 bits.
Funções gráficas
Foram implementadas também funções gráficas para desenhar e/ou preencher: pontos, linhas, retangulos e círculos. Para tanto, foram utilizadas as funções matemáticas descritas na seção anterior, bem como, os cálculos dos pontos (pixels) representantes da forma a ser desenhada ou pintada.
Foi implementada também a técnica de double buffering para que o desenho dos gráficos não tivesse o efeito de piscar. Logo, ao invés de chamar a devida interrupção da bios para pintar todos os pixels a serem mostrados em um determinado instante, se armazena todos os pixels primeiro em uma região da memória principal e, depois, transfere-se esses dados para uma região especial da memória que, dependendo do modo de vídeo escolhido, essa região de memória é lida e as cores dos pixels são pintadas na tela de uma vez só.
Séries de tailor
As séries de tailor são uma tentativa de se aproximar uma soma de termos de um polinômio do resultado de uma função. As séries costumam ser infinitas. Logo, quanto maior o número de termos, mais próximo do valor real é o resultado da função.
As séries de tailor foram utilizadas para o cálculo aproximado das funções matemáticas de potência, raiz quadrada e funções trigonométricas. Dado que, a arquitetura 8086 não dispõe dessas funções. Em relação as funções trigonométricas, as séries de tailor para as funções: seno, cosseno, só têm um valor aproximado, em torno de, entre, 0° e 90°. Logo, foram feitos cálculos de simetria e espelhamento para os ângulos dos demais quadrantes.
O gerenciador de boot
Foi necessário criar um pequeno gerenciador de boot gravado no setor MBR da imagem que carrega o restante do jogo na memória principal.
O jogo de breakout
O jogo de breakout utiliza as funções descritas anteriormente. Isto é, as funções gráficas para que se possa visualizar os gráficos do jogo, e as funções matemáticas e números de ponto flutuante.
Conceitos de física como, reflexão em linha reta e alteração do ângulo de reflexão, foram utilizados para o movimento da bolinha no jogo. Foi tratada também a detecção de colisão entre a bolinha, os quadradinhos, a raquete e as paredes.
Foi implementado o mecanismo de pausa que para a execução do jogo e movimentos da bolinha.
O Jogo tem também suporte ao reinicio que acontece quando a tecla ESC é pressionada.
Finalizando...
É isso pessoal, espero que tenham gostado e, até o próximo!