EIC0020 – Laboratório de Computadores
2009/2010 – 2S
ARKANOID
Turma 5, Grupo 3
Francisca Teixeira - 090509139 – [email protected]
Ricardo Cunha – 080509117 – [email protected]
Faculdade de Engenharia da Universidade do Porto
Rua Roberto Frias, s/n, 4200-465 Porto, Portugal
Maio, 2010
Laboratório de Computadores | T5G03
Declaração de originalidade
Declaramos sob compromisso de honra que este trabalho nas suas partes
constituintes de código e relatório é original e da nossa autoria, não correspondendo,
portanto, a cópia ou tradução de outros trabalhos já realizados, na FEUP ou fora dela.
Mais declaramos que todos os documentos ou código que serviram de base ao
desenvolvimento do trabalho descrito no relatório e seus anexos são adequadamente
citados e explicitados e que todas as eventuais partes transcritas ou utilizadas de
outras fontes estão devidamente assinaladas, identificadas e evidenciadas.
Subscrevemos a declaração acima:
Francisca Teixeira e Ricardo Cunha
2
Laboratório de Computadores | T5G03
Índice
1.Resumo ..................................................................................................................................................... 4
2. Descrição do Programa ............................................................................................................................ 5
Interface do jogo: ................................................................................................................................. 5
Regras do jogo: .................................................................................................................................... 5
3. Implementação ......................................................................................................................................... 6
3.1.Arquitectura do Programa................................................................................................................... 6
Módulos do trabalho: ............................................................................................................................ 6
3.2. Funcionalidades ................................................................................................................................ 7
Funcionalidades implementadas: ......................................................................................................... 7
Funcionalidades não especificadas mas implementadas:.................................................................... 7
Limitações do programa: ...................................................................................................................... 7
3.3 Detalhes Relevantes da Implementação ............................................................................................ 8
3.4 Instruções de compilação e utilização ................................................................................................ 8
3.5 Funcionamento do programa.............................................................................................................. 8
4. Conclusões ............................................................................................................................................... 9
5. Referências ............................................................................................................................................... 9
6. Anexos .................................................................................................................................................... 10
Anexo A – Documentação do Código..................................................................................................... 10
game.h ............................................................................................................................................... 10
video-graphics.h ................................................................................................................................. 12
sprite.h ............................................................................................................................................... 13
timer.h ................................................................................................................................................ 15
kbc.h................................................................................................................................................... 16
music.h ............................................................................................................................................... 19
ints.h................................................................................................................................................... 20
gqueue.h ............................................................................................................................................ 21
Anexo B – Diagrama UML ...................................................................................................................... 23
Anexo C – Diagrama de Chamadas de funções..................................................................................... 24
Anexo D – Histórico de Desenvolvimento .............................................................................................. 25
Anexo E – Makefile................................................................................................................................. 27
Anexo F – Proposta inicial ...................................................................................................................... 28
3
Laboratório de Computadores | T5G03
1.Resumo
O presente relatório foi realizado no âmbito da disciplina de Laboratórios de
Computadores, do 2º Semestre, 2º Ano, do Mestrado Integrado em Engenharia
Informática e Computação, da Faculdade de Engenharia da Universidade do Porto.
O objectivo foi criar, em linguagem C estruturada, uma aplicação que
integrasse os diversos periféricos estudados na disciplina. Foram também usadas
várias ferramentas de desenvolvimento de software, como SVN, MAKEFILES ou
gerador de documentação DOXYGEN.
Optou-se por criar um jogo, baseado no existente ARKANOID, do tipo breakout.
Relativamente aos periféricos, foram incluídos:

Teclado, para seleccionar menus e mover a tabela durante o jogo;

Placa em modo gráfico com animação de sprites e texto;

RTC, para periodicamente contar o tempo, e para obter a hora actual;

Timer 2 e altifalante do sistema, para poder reproduzir as várias músicas e
sons do jogo;
Durante todo o processo foram usadas com frequência as ferramentas de
desenvolvimento, nomeadamente:

MAKEFILES,
que
gerem
os
ficheiros
do
projecto
e
respectivas
dependências e simplificam o processo de compilação;

GDB, um debugger que permite facilmente encontrar erros na aplicação;

SVN, software de controlo de versões usado para manter o código e o seu
histórico num servidor.

DOXYGEN, gerador de documentação, o qual exigiu comentários em todos
os ficheiros que constituem a aplicação.
4
Laboratório de Computadores | T5G03
2. Descrição do Programa
O projecto desenvolvido baseia-se no conhecido jogo “Arkanoid”, apesar de
naturais limitações em relação ao jogo original. No começo, o programa pergunta
ainda na linha de comandos o nome do jogador. Depois do utilizador fornecer o
seu nome (ou nick) ao programa este entre no modo gráfico, onde será
apresentado um Menu. Aqui o utilizador terá quatro opções: Start Game (iniciar
jogo), Show Best Scores (mostrar os melhores resultados), Show Instructions
(mostrar as instruções do jogo) e Exit (sair do programa).
Interface do jogo:
No decorrer do jogo, estarão presentes os seguintes elementos gráficos,
visualizados pelo utilizador:

tabela movível pelo utilizador através do teclado, que se situa na parte do
inferior do ecrã;

bola que é animada e movimenta-se pelo ecrã;

blocos que deverão ser destruídos pela bola, quando esta embate nos
mesmos e estarão presentes na zona central do ecrã;

duas paredes e um tecto, que simbolizam os limites na cena e são
representados por longas barras na vertical e na horizontal.
Também será apresentado no ecrã, na parte superior:

o nome do jogador;

o nível actual;

o score actual;

o número de vidas restantes;
Regras do jogo:
Em cada nível, o jogador terá de controlar o movimento horizontal da
tabela, de forma a manter a bola em movimento, para que esta embata e destrua
um total de 30 blocos. A bola irá sofrer desvios através de embates nas paredes,
no tecto, na tabela movível e nos próprios blocos. Por cada bloco atingido, o
jogador ganha 200 pontos, que será colocado imediatamente no seu score. Depois
de ter derrubado todos os blocos, o nível acaba, passando para o seguinte, onde
volta a encontrar 30 blocos. No entanto, e como já é um nível superior, a
5
Laboratório de Computadores | T5G03
velocidade da bola irá aumentar, o que dificultará a tarefa ao jogador de
acompanhar a trajectória da mesma.
O jogador tem no máximo três vidas. Ou seja, não pode deixar que a bola
atinja a parte inferior do ecrã mais de três vezes. Caso contrário perde o jogo, e o
seu score actual irá ser comparado com os dos melhores (presentes no ficheiro
bestscores.txt) e colocado neste caso seja um dos dez melhores resultados.
3. Implementação
3.1.Arquitectura do Programa
Módulos do trabalho:

Main – este módulo é o responsável pela instalação e desinstalação das
interrupções, entrada e saída do modo gráfico, e chamada função
startMenu presente no módulo Game, depois de perguntar o nome ao
jogador.

Game – este é o módulo mais importante de todo o projecto desenvolvido.
É responsável por criar o menu, o ambiente de jogo, a visualização das
melhores pontuações efectuadas e o controlo das acções feitas pelo
utilizador.

Sprite – contém as funções essenciais para a construção de sprites. Cria
um sprite a partir da leitura de um pixmap, desenha o sprite no ecrã, anima
os sprites que se movem no mesmo ecrã e destrói os mesmos.

Video Graphics – contém as funcionalidades necessárias para o uso da
placa gráfica no modo gráfico. Destas funcionalidades, incluem-se a entrada
e saída do modo gráfico, o preenchimento de pixels no ecrã e também o
desenho de caracteres no modo gráfico.
 Ints – este módulo contém as funções de instalação e desinstalação de
interrupções (por exemplo, o teclado) e também de habilitar/desabilitar
PIC’s.
 Music – contém as funções necessárias ao uso de sons no programa,
especialmente as frequências das notas musicais.
 KBC – controlador do teclado que contém as funções relativas à utilização
do mesmo.
6
Laboratório de Computadores | T5G03
 Timer – activa/desactiva as interrupções necessárias no timer.
 RTC – Este módulo inclui a leitura/escrita no RTC, bem como a função de
interrupção escrita em C, e que é usada para a utilização dos sons
presentes no programa.
 Queue – contém algumas funções típicas de gerenciamento de uma pilha
(first in-first out). Além de inicializar a fila, tem as operações de adicionar e
remover elementos da pilha. Esta é do tipo char.
 Queue Genérica – semelhante à Queue. No entanto pode aceitar elementos
de outros tipos.
Há ainda a referir o módulo Utypes que contém algumas definições para
simplificar a escrita do código. Faz ainda parte do programa uma função assembly:
kbd_handler que é um handler da interrupção do teclado.
3.2. Funcionalidades
Funcionalidades implementadas:

Controlo de interrupções do teclado, do TIMER0 e do RTC;

Sons especiais de acordo com o evento, usando interrupções do RTC;

Sprites animados;

Escrita de texto em modo gráfico;

Introdução das teclas numa queue (através da interrupção em Assembly) e
leitura a partir da mesma.
Funcionalidades não especificadas mas implementadas:

Informação sobre o jogador (nome, vidas, nível, score, etc.) na parte
superior do ecrã.
Limitações do programa:

Impossibilidade de bónus enviados para baixo (depois de um bloco ser
destruído), para ser apanhado pela tabela (exemplos de bónus: tabela
maior, mais pequena, mais bolas, etc..).
7
Laboratório de Computadores | T5G03
3.3 Detalhes Relevantes da Implementação
Os blocos são criados a cada novo jogou (ou nível), para assim poder
serem criados blocos coloridos diferentes aleatoriamente. As interrupções do
teclado são tratadas através da função em assembly kbd_handler, que guarda
a informação da tecla (scancode) numa queue. Através de uma máquina de
estados, o programa consegue saber se está no menu ou no ambiente do jogo
está e assim processar devidamente a informação transmitida pelo teclado.
Os sons produzidos no jogo são efectuados a partir da rotina de
interrupção do RTC (escrita em C), onde também funciona dentro duma
máquina de estados.
A qualquer momento do jogo, o jogador pode carregar na tecla ESC,
onde será enviado directamente para o menu, saindo assim do jogo actual.
3.4 Instruções de compilação e utilização
A ligação do programa e de todos os módulos pode ser efectuada através
do uso de uma MAKEFILE. Para compilar pode executar-se na consola:

make – gera um executável chamado akanoid.exe, todos os ficheiros de
código e cabeçalhos e o ficheiro kbc_init.o devem estar na mesma
directoria da makefile, local onde é executado o comando make;
Para proceder a uma limpeza do código (eliminando todos os ficheiros
terminados em *.o) pode executar-se:

make clean – limpa todos os ficheiros *.o presentes na directoria onde é
executado o comando (o ficheiro kbc_init.o não é eliminado);
Para invocar o programa basta, apenas, chamar o executável, sem
quaisquer parâmetros adicionais.
Durante a execução do programa é possível sair do jogo carregando na
tecla ESCAPE, desde que o jogo se encontre a decorrer.
3.5 Funcionamento do programa
O programa começa por pedir o nome ao jogador. Após esse primeiro
momento, o jogador é imediatamente levado até ao Menu, onde pode começar um
jogo novo, ver os melhores resultados, ver as instruções do jogo ou sair do
programa. O jogador escolhe a opção com ↑ (seta para cima) ou ↓ (seta para
8
Laboratório de Computadores | T5G03
baixo). Após carregar ENTER, o programa escolhe a opção seleccionada no ecrã
pela tabela do jogo.
Caso o jogador inicie um novo jogo será levado para o ambiente jogável,
onde pode interagir com a cena através de três teclas:

, para mover a tabela para a esquerda;

, para mover a tabela para a direita.
Durante a execução do programa é também possível sair do jogo
carregando na tecla ESCAPE, desde que o jogo se encontre a decorrer.
4. Conclusões
Este
trabalho
serviu
essencialmente
para
aprofundar
e
aplicar
conhecimentos adquiridos previamente nas aulas práticas. Permitiu uma boa
aprendizagem sobre como interligar todos os componentes que haviam sido
tratados separadamente. Possibilitou também entender, de uma forma mais prática
e real, qual o uso de todos os periféricos usados na disciplina. Ao longo do
desenvolvimento do projecto, apesar de terem sido encontradas algumas
dificuldades em diversos pontos, foi sempre prestada a devida ajuda, quer devido
às explicações das aulas teóricas, quer no auxílio das aulas práticas. Foram
encontradas dificuldades iniciais na instalação/desinstalação das interrupções bem
como na gestão de todas as interrupções em simultâneo. No final, conseguimos
colmatar e gerir com sucesso essas dificuldades. Caso fosse possível, existiriam
alguns melhoramentos a fazer ao programa:

Utilizar o rato como periférico;

Criar menu que permitisse ao utilizador pequenas configurações, como ligar
o som;
5. Referências
[1] DJGPP - http://www.delorie.com/djgpp/
[2] NASM - http://www.nasm.us/
[3] Makefile - http://www.gnu.org/software/make/
[4] SVN - http://subversion.tigris.org/
[5] Doxygen - http://www.stack.nl/~dimitri/doxygen/
[6] Microsoft Windows 98 - http://www.microsoft.com/en/us/default.aspx
9
Laboratório de Computadores | T5G03
6. Anexos
Anexo A – Documentação do Código
game.h
/**
Variáveis para comparar colisões
*/
#define MAX_LEN 600
#define WALL_HIT 0x01
#define ROOF_HIT 0x02
#define TABLE_HIT 0x03
#define BLOCK_HIT 0x04
#define GROUND_HIT 0x05
/**
Enumeraçãoe e variável que permite determinar o estado em que a
aplicação se encontra
*/
enum STATES {MENU, JOGO};
int state;
/**
Pilha que guarda os scancodes obtidos do teclado, de forma a processálos devidamente
*/
Queue *kbd_queue;
/**
Estrutura que guarda toda a informação relativa a um jogo, e que
permite inicializá-lo
*/
typedef struct {
char player[20];
int level;
int score;
int lives;
Sprite* table;
Sprite* roof;
Sprite* leftWall;
Sprite* rightWall;
Sprite* ball;
//Sprite* block;
Sprite*** blocks;
} Game;
/**
Estrutura que guarda as melhores pontuações obtidas no jogo
*/
typedef struct {
char player[20];
int score;
} BestScores;
/**
10
Laboratório de Computadores | T5G03
Gera nºs aleatorios entre 0 e 8 para escolher um bloco dos oito
existentes para desenhar
*/
int n_random();
/**
Cria blocos para mostrar no ecrã de jogo, usando aleatoriamente a
funcao n_random()
*/
Sprite*** createBlocks(char* base, int nrows, int ncol);
/**
Coloca na base "principal" o conteúdo da base "temporária"
*/
void refreshScreen(char* base, char* basetmp);
/**
Verifica colisões da bola (paredes, tecto, blocos e barra movivel)
*/
int check_colision(Sprite * sprite, char* base, int x, int y);
/**
Actualiza o buffer temporário para depois copiar para a base
*/
void actualizar(char* baseTmp, Game* game);
/**
Coloca o bloco apontado por block a preto para não aparecer no ecrã e
não afectar as colisões
*/
void setBlackBlock(Sprite* block);
/**
Verifica se todos os blocos estão a preto
*/
Bool allBlackBlocks(Game* game);
/**
Processa as colisões ocorridas entre a bola e os vários elementos
*/
void process_colision(Game* game, int colision, char* base);
/**
Acrescenta o score final às melhores pontuacões caso o score for
melhor que as 10 melhores já existente
*/
void newBestScores(char* base, Game* game);
/**
Inicia um novo jogo, tendo em conta a nova estrutura "Game" criada.
*/
void startGame(char* base, char* baseTmp, Game* game);
/**
Liberta memória de uma estrutura Game passada como argumento.
*/
void destroy_game(Game* game);
/**
11
Laboratório de Computadores | T5G03
Cria um novo jogo, ou seja, cria todos os elementos gráficos
necessários ao jogo e um segundo buffer,
necessário para o bom funcionamento do programa. De seguida chama a
função void startGame(char* base, char* baseTmp, Game* game)
*/
void createGame(char* base, Game* game);
/**
Mostra as instruções do jogo
*/
void showInstructions(char* base);
/**
Mostra as melhores pontuações até ao momento
*/
void showBestScores(char* base);
/**
Processa os acontecimentos do teclado, dependendo do estado em que o
programa se encontra
*/
int process_kbd(char* base, Game* game);
/**
Mostra o menu principal e permite escolher a opcão desejada
*/
void startMenu(char* base);
video-graphics.h
/** @defgroup Video Video
* @{
* Entering/leaving/utility video functions
*/
/*
* there are two global variables, declared (but not defined) here
*/
int HRES; /**< global variable with the horizontal resolution in
pixels */
int VRES; /**< global variable with the vertical resolution in pixels
*/
#define
#define
#define
#define
#define
CHAR_H 16
MODE_640x480 0x101
MODE_800x600 0x103
MODE_1024x768 0x105
MODE_1280x1024 0x107
/** Returns the video memory address.
*/
ulong get_video_addr(int mode);
/** Enter graphics mode, enabling near pointers and mapping video
physical memory
* to program virtual address.
*
* Returns a generic pointer pointing to video memory address or NULL
on error.
12
Laboratório de Computadores | T5G03
* "mode" specifies the VESA graphics mode to use, and
* the mapping information is returned through "map".
*
* Also initializes two global variables, VRES and HRES,
*/
char * enter_graphics(int mode, __dpmi_meminfo *map);
/** Unmap video memory, disable near pointer and returns to text mode
*/
void leave_graphics(__dpmi_meminfo map);
/** Draws a pixel of color "color" at screen coordinates x, y at
memory address "base"
*/
void set_pixel(int x, int y, int color, char *base);
/** Returns the pixel color at screen coordinates x, y at memory
address "base"
*/
int get_pixel(int x, int y, char *base);
/** Set graphics memory at memory address "base" to "color".
*/
void clear_screen(char color, char *base);
/** Draw a line of color "color" between point (xi,yi) and (xf,yf) at
memory address "base"
*/
void draw_line(int xi, int yi, int xf, int yf, int color, char *base);
/** Desenha um caracter c em xi e yi, com cor fore_color e background
back_color, redimensionado char_scale.
*/
void drawCharAt(char c, int xi, int yi, int fore_color, int
back_color, int char_scale, char* video_base, char *table);
/** Desenha uma string s em x_ori e y_ori, com cor fore_color e
background back_color, redimensionado char_scale.
*/
void drawStringAt(char* s, int xi, int yi, int fore_color, int
back_color, int char_scale, char* video_base, char *table);
/** Desenha um inteiro num em xi e yi, com cor fore_color e background
back_color, redimensionado char_scale.
*/
void drawIntAt(int num, int xi, int yi, int fore_color, int
back_color, int char_scale, char* video_base, char *table) ;
/** @} end of video */
sprite.h
/** @defgroup Sprite Sprite
* @{
* Sprite related functions
*/
/** A Sprite is an "object" that contains all needed information to
* create, animate, and destroy a pixmap. The functions assume that
13
Laboratório de Computadores | T5G03
* the background is BLACK and they take into account collision with
* other graphical objects or the screen limits.
*/
typedef struct {
int x, y;
///< current sprite position
int width, height;
///< sprite dimensions
int xspeed, yspeed; ///< sprite current speed in the x and y
direction
char *map;
///< the sprite pixmap (use read_xpm())
} Sprite;
#define
*/
#define
#define
#define
MAX_SPEED 5
/**< each sprite maximum speed in pixels/frame
RIGHT_HIT 2
LEFT_HIT 3
MOUSE_HIT 4
/**< collision with right block (WHITE) */
/**< collision with left block (WHITE)
*/
/**< collision with mouse (LIGHTMAGENTA) */
/** Reads a xpm-like sprite defined in "map" (look at pixmap.h for
* examples). Returns the address of the allocated memory where the
* sprite was read. Updates "width" and "heigh" with the sprite
* dimension. Return NULL on error.
* Assumes that VRES and HRES (the screen vertical and horizontal
resolution)
* are externaly defined.
*
* Usage example, using the defined sprite in pixmap.h:
* <pre>
*
#include "pixmap.h" // defines pic1, pic2, etc
*
int wd, hg;
*
char *sprite = read_xpm(pic1, &wd, &hg);
* </pre>
*/
char *read_xpm(char *map[], int *width, int *height);
/** Creates with random speeds (not zero) and position
* (within the screen limits), a new sprite with pixmap "pic", in
* memory whose address is "base".
* Returns NULL on invalid pixmap.
*/
Sprite * create_sprite(char *pic[], char *base);
void draw_sprite(Sprite* sprite, char *base);
/** Animates the figure, giving it the new position calculated with
the values of its speed
*/
void animate_sprite(Sprite *fig, char *base);
/** The "fig" sprite is erased from memory whose address is "base"
* and used resources released.
*/
/**
Liberta a memória da sprite passada como argumento
*/
void destroy_sprite(Sprite *sprite);
/**
Apaga a sprite do buffer base conseiderado
*/
void clear_sprite(Sprite *sprite, char *base);
14
Laboratório de Computadores | T5G03
timer.h
/** @defgroup TimerCounter TimerCounter
* @{
*
* Timer-Counter definitions
*/
/** @name Timer Address */
/*@{*/
#define TIMER_0
0x40 ///<
#define TIMER_1
0x41 ///<
#define TIMER_2
0x42 ///<
#define TIMER_CTRL
0x43 ///<
register
/*@}*/
/** @name Speaker and Timer2
/*@{*/
#define SPEAKER_CTRL
0x61
register, whose bits 0 and 1
the speaker
#define TIMER2_ENABLE (1 <<
#define SPEAKER_ENABLE (1 <<
/*@}*/
Adress of Timer0 divider
Adress of Timer1 divider
Adress of Timer2 divider
The address of the timer control
control and bit meanings */
///< The address of a generic PC
control the timer2 clock and output to
0) ///< Enable Timer 2 clock
1) ///< Enable Timer 2 output to speaker
/** @name Some usefull (and nice) definitions */
/*@{*/
#define TIMER_CLK
1193181 ///< The timers input frequency
#define LCOM_MODE 0x36
///< Control byte: LSB followed by MSB,
mode 3, binary count
#define LSB(i) ((i) & 0xFF)
///< The Least Significative Byte of a
Word
#define MSB(i) ((i) >> 8)
///< The Most Significative Byte of a
Word
/*@}*/
/** Program timer (0,1,2) with mode
*/
void timer_init(int timer, int mode);
/** Load timer (0,1,2) with value
*/
void timer_load(int timer, int value);
/** Wait mili miliseconds, indirectly counting T0 interrupts
*/
void mili_sleep(int mili);
/** wait secs seconds, indirectly counting T0 interrupts
*/
void sec_sleep(int secs);
/** @} end of TimerCounter *
15
Laboratório de Computadores | T5G03
kbc.h
/** @defgroup KeyboardController KeyboardController
* @{
*
* Keyboard and Mouse related functions
*/
#define KBC_TIMEOUT 30 ///< maximum amount of milliseconds to wait for
KBC response/availability
/** @name The hardware register addresses */
/*@{*/
#define CMD_REG
0x64 ///< command register (read only)
#define STAT_REG 0x64 ///< status register (write only)
#define DATA_REG 0x60 ///< data register
(read/write)
/*@}*/
/** @name Bit meanings in the
/*@{*/
#define OBF
(1 << 0) ///<
#define IBF
(1 << 1) ///<
#define AUX
(1 << 5) ///<
interface
#define PAR_ERR (1 << 7) ///<
#define TO_ERR (1 << 6) ///<
/*@}*/
status register */
Output Buffer Full
Input Buffer Full
1 if data at DATA_REG came from mouse
Parity Error
Timeout Error
/** @name "Historical" commands to send to DATA_REG, response in
DATA_REG */
/*@{*/
#define ResetKBC
0xFF ///< Reset the KBC interface
#define DefaultKBD 0xF6 ///< Set default scancode and repeat rate
#define DisableKBD 0xF5 ///< Historical Disable keyboard
#define EnableKBD 0xF4 ///< Historical clear buffer and enable
keyboard
#define KBDRate
0xF3 ///< Keyboard repeat rate, one arg, bits 0-4
repeat rate, bits 5-6 start delay
#define WriteLEDS 0xED ///< Turn on/off KBD LEDS, one arg, one bit
per led, bits 0-2, 0-off, 1-on
#define SCROLL_LOCK (1 << 0) ///< SCROLL_LOCK led for WriteLEDS
command
#define NUM_LOCK
(1 << 1) ///< NUM__LOCK led for WriteLEDS command
#define CAPS_LOCK
(1 << 2) ///< CAPS_LOCK led for WriteLEDS command
/*@}*/
/** @name Response
/*@{*/
#define ACK
#define Resend
commands the whole
#define Error
/*@}*/
codes to commands/data written in DATA_REG */
0xFA ///< Acknowledge OK response
0xFE ///< Resend error response; on multibyte
command must be resent from the beginning
0xFC ///< Error
/** @name Command codes to
DATA_REG, return values in
/*@{*/
#define ReadCommand
0x20
#define WriteCommand 0x60
#define DisableMouse 0xA7
send to CMD_REG, args, if exists, to
DATA_REG */
///< Read Command_Byte
///< Write Command_Byte, one arg
///< Disable Mouse Interface
16
Laboratório de Computadores | T5G03
#define EnableMouse
#define TestMouse
#define Test8042
on error
#define TestKBD
#define NDisableKBD
keyboard
#define NEnableKBD
keyboard
#define WriteMouse
for the Mouse"
#define ResetPC
/*@}*/
0xA8 ///< Enable Mouse Interface
0xA9 ///< Test Mouse Interface, returns 0 if OK
0xAA ///< Test KBC, returns 0x55 if sucess, 0xFC
0xAB ///< Test mouse, returns 0 if OK
0xAD ///< New (versus historical) Disable
0xAE ///< New (versus historical) Enable
0xD4 ///< Write Mouse, one arg, see "Commands
0xFE ///< Reset PC (reboot)
/** @name Bit meanings in the Command_Byte
* (read/write with command ReadCommand/WriteCommand)
*/
/*@{*/
#define INT_1
(1 << 0) ///< Enable generation of interrupts from
keyboard
#define INT_12
(1 << 1) ///< Enable generation of interrupts from
mouse
#define EN_KBD
(1 << 4) ///< Enable keyboard interface (zero
enables, one disables)
#define EN_MOUSE (1 << 5) ///< Enable mouse interface (zero enables,
one disables)
/*@}*/
/** @name Bit meaning
*/
/*@{*/
#define YOVF (1 << 7)
#define XOVF (1 << 6)
#define YSGN (1 << 5)
#define XSGN (1 << 4)
#define MBT (1 << 2)
#define RBT (1 << 1)
#define LBT (1 << 0)
/*@}*/
in first byte of mouse data packet
///<
///<
///<
///<
///<
///<
///<
X overflow
Y overflow
Sign of data packet byte 3 (y movement)
Sign of data packet byte 2 (x movement)
Middle button
Right button
Left button
/** @name Utility macros to inquiry first byte of mouse data packet */
/*@{*/
#define LEFT_BUTTON(dt)
(((dt) & LBT) == LBT) ///< 1 if left button
pressed
#define RIGHT_BUTTON(dt) (((dt) & RBT) == RBT) ///< 1 if right button
pressed
#define MIDDLE_BUTTON(dt) (((dt) & MBT) == MBT) ///< 1 if middle
button pressed
#define Y_OVERFLOW(dt)
in x movement
#define X_OVERFLOW(dt)
in y movement
(((dt) & XOVF) == XOVF) ///< 1 if overflow
(((dt) & YOVF) == YOVF) ///< 1 if overflow
#define X_SIGN(dt)
(((dt) & XSGN) == XSGN ? -1 : 1) ///< 1 if
positive x movement, -1 if negative
#define Y_SIGN(dt)
(((dt) & YSGN) == YSGN ? -1 : 1) ///< 1 if
positive y movement, -1 if negative
/*@}*/
17
Laboratório de Computadores | T5G03
/** Initializes the KeyBoard Controller. If 'debug' is not 0 every
* read or write to the KBC, together with the read or writed data is
* echoed to the screen. In this mode the function name being executed
* is printed followed by a ':', add=xx means the I/O address written,
* and data=xx the data read or written.
*
* A 1 is returned if a mouse is found.
*
* The function starts to flush any pending data in the KBC, reading
* the data register until a timeout is received.
*
* Then it enables the KBC mouse interface, send a MouseReset to the
* mouse and checks for the correct answer (0xFA, 0xAA then 0x00). If
* the mouse was detected, data streaming is disabled (StreamDisable),
* SampleRate is set to 100, Resolution is set to 8 counts/mm, Scaling
* is set to 1:1, the mouse interrupts generation are enabled at the
* KBC (not at the PIC!), and data streaming enabled
* (StreamEnable). All this (but StreamEnable) shouldn't be necessary,
* as MouseReset is supposed to do it properly.
*
* The KBDRate is also set to its maximum speed.
*
* Uses write_kbc_cmd(), write_kbc_data(), read_kbc() and write_aux()
*
*/
void kbd_handler(void);
/** Write 'data' to the command register, returning 0 for OK or -1 on
* timeout.
*
* Uses write_kbc()
*/
int write_kbc_cmd( unsigned data);
/** Returns 1 if a DOS mouse driver is installed, 0 if not.
*
* Needed to know if a DOS mouse driver is installed in order
* to reinstall it at program end.
*
*/
/** Write 'data' to the data register, returning ACK, Error or -1 on
timeout.
*
* If a Resend reply is received from the KBC, it retries up to 3
times to
* write the data.
*
* Uses write_kbc() and read_kbc()
*/
int write_kbc_data( unsigned data);
/** Send 'cmd' to the mouse, prefacing it with the WriteMouse command
* to the command register.
* If a Resend reply is received from the KBC, it retries up to 3
times to write 'cmd', resending the whole sequence.
* * Uses write_kbc_cmd(), write_kbc() and read_kbc()
*/
int write_aux(unsigned cmd);
18
Laboratório de Computadores | T5G03
/** Returns the data read a the data register.
*
* Waits for OBF on status register up to KBC_TIMEOUT milliseconds,
* then reads and returns the data read at the data register. Returns
* -1 on timeout or transmission error.
*/
int read_kbc(void);
/** Write 'data' at IO address 'adr' , returning -1 on error or
timeout.
*
* Waits for IBF on status register , than writes data to 'adr',
* return -1 on timeout.
*/
int write_kbc(unsigned adr, unsigned data);
/** @} end of KeyboardController */
music.h
/** @defgroup Music Music
* @{
*
* Music related functions
*/
/** Note definition
*/
typedef struct {
int freq;
/**< note frequency */
int dur;
/**< note duration in miliseconds */
} Note;
/** Song definition
*/
typedef struct {
int lenght;
/**< number of notes */
int pause;
/**< pause between notes (ms) */
Note *notes;
/**< pointer to array of notes */
} Song;
/** Turns the speeker on
*/
void speaker_on();
/** Turns the speeker off
*/
void speaker_off();
/** Plays a single note
*/
void play_note(Note *note);
/** Plays a song using busy-waiting
<pre>
usage example:
Note notes[] = {{Sol6, 100}, {Mi6,50}, {Sol6, 50}, {Mi6, 25}};
Song s = { sizeof(notes)/sizeof(Note), 10, notes};
19
Laboratório de Computadores | T5G03
play_song(&s);
</pre>
*/
void play_song(Song *s);
ints.h
/** @defgroup interrupts Interrupts
* @{
*
* Interrupt related functions
*/
/** @name PIC registers address */
/*@{*/
#define EOI
0x20 ///< End Of Interrupt Command
#define PIC1_CMD 0x20 ///< PIC1 register address to
#define PIC2_CMD 0xA0 ///< PIC2 register address to
#define PIC1_MASK 0x21 ///< PIC1 register address to
interrupt mask */ <-----------#define PIC2_MASK 0xA1 ///< PIC2 register address to
interrupt mask */
/*@}*/
*/
send EOI */
send EOI */
read/write
read/write
/** @name PC Interrupts */
/*@{*/
#define T0_IRQ
0 ///< Timer 0
<--------------#define KBD_IRQ
1 ///< keyboard
#define COM2_IRQ 3 ///< serial port 2
#define COM1_IRQ 4 ///< serial port 1
#define FLP_IRQ
6 ///< floppy
#define LPT_IRQ
7 ///< parallel port
#define RTC_IRQ
8 ///< realtime clock
#define MOUSE_IRQ 12 ///< mouse
#define FPU_IRQ
13 ///< Floating point
#define DISK1_IRQ 14 ///< Hard disk controller 1
#define DISK2_IRQ 15 ///< Hard disk controller 2
/*@}*/
/** @name Some usefull definitions */
/*@{*/
/** Gives mask bit associated with a given irq.
* <em>Warning</em>, if irq > 7 the result must be applied to PIC2
*/
#define IRQ_MASK_BIT(irq) ((irq) < 8 ? 1 << (irq) : (1 << (irq)) >> 8)
/** gives the vector associated with a given IRQ */
#define IRQ_VECTOR(irq) ((irq) < 8 ? (irq) + 0x08 : (irq) - 8 + 0x70)
/*@}*/
//void irq_func(void);
/** Installs the ASM written function 'irq_func' as the interrupt
* handler associated with interrupt 'irq', updating the 'old_irq'
* structure with the current interrupt handler. Returns 0 on success
* or -1 on error, in which case the original interrupt handler
* remains installed.
20
Laboratório de Computadores | T5G03
*
* See reinstall_asm_irq_handler() to reinstall the original handler.
*/
int install_asm_irq_handler(int irq, void (*irq_func)(void),
_go32_dpmi_seginfo *old_irq);
/** Installs the C written 'irq_func' interrupt handler at the
* interrupt handler associated with interrupt 'irq', updating the
* old_irq structure with the current interrupt handler. Returns 0 on
* success or -1 on error, in which case the original interrupt
* handler remains installed.
*
* See reinstall_c_irq_handler() to reinstall the original handler.
*/
int install_c_irq_handler(int irq, void (*irq_func)(void),
_go32_dpmi_seginfo *old_irq);
/** Reinstalls the interrupt handler specified in 'old_irq' for
interrupt
* 'irq'. See install_asm_irq_handler().
*/
void reinstall_asm_irq_handler(int irq, _go32_dpmi_seginfo *old_irq);
/** Reinstalls the interrupt handler specified in 'old_irq' for
interrupt
* 'irq'. See install_c_irq_handler().
*/
void reinstall_c_irq_handler(int irq, _go32_dpmi_seginfo *old_irq);
/** Mask the bit corresponding to 'irq', disabling its interrupts.
* The correct PIC is used.
*/
void disable_irq(int irq);
/** Unmask the bit corresponding to 'irq', enabling its interrupts.
* The correct PIC is used.
*/
void enable_irq(int irq);
/** @} end of interrupts */
gqueue.h
/ Generic Queue definition
typedef struct {
void *ptr;
///<
int in;
///<
int out;
///<
from
int cnt;
///<
int size;
///<
int ele_size;
///<
} GQueue;
generic pointer for a queue
index on array where to put next element
index on array where to get next element
current number of elements in the queue
queue capacity
size of the element to put in the queue
/** Initialize the queue
*/
GQueue * newGQueue(int n_ele, int size_ele);
21
Laboratório de Computadores | T5G03
/** Delete the queue
*/
void deleteGQueue(GQueue *q);
/** Put ele in the queue pointed to by 'q'
* Returns false if operation failed (the queue is full)
*/
Bool putGQueue(GQueue *q, void *ele);
/** Get next element from queue
* Returns -1 (an int) if there are no elements in the queue
*/
void * getGQueue(GQueue *q);
/** Returns true if the queue is empty
*/
Bool isEmptyGQueue(GQueue *q);
/** Returns true if the queue if full
*/
Bool isFullGQueue(GQueue *q);
utypes.h
/** @defgroup UserTypes UserTypes
* @{
*
* Typedefs for lazzy programmers
*/
typedef unsigned
unsigned char
typedef unsigned
typedef unsigned
typedef unsigned
char uchar;
///< uchar is shorter to type than
short ushort; ///< ushort is an unsigned short
int uint;
///< uint is an unsigned int
long ulong;
///< ulong is an unsigned long
typedef unsigned char Byte;
typedef unsigned short Word;
///< 8 bits, only on i386
///< 16 bits, only on i386
/** User defined boolean type
* <pre>
* usage example:
* Bool done = false;
* while (done == false) {...}
* </pre>
*/
typedef enum {
false = 0, ///< the false value
true = 1 ///< the true value
} Bool; ///< user defined boolean type
/**@} end of user types */
22
Laboratório de Computadores | T5G03
Anexo B – Diagrama UML
23
Laboratório de Computadores | T5G03
Anexo C – Diagrama de Chamadas de funções
24
Laboratório de Computadores | T5G03
Anexo D – Histórico de Desenvolvimento
27 Maio 2010
r66 (Actualizações no relatório e modificações nas colisões) committed by ricardo.cunha.mieic r65 ([No log message]) committed by ricardo.cunha.mieic - [No log message]
r64 ([No log message]) committed by klfrancisca - [No log message]
r63 ([No log message]) committed by klfrancisca - [No log message]
r62 ([No log message]) committed by klfrancisca - [No log message]
r61 ([No log message]) committed by klfrancisca - [No log message]
r60 ([No log message]) committed by ricardo.cunha.mieic - [No log message]
r59 (Pequenas alterações nas colisões dos blocos) committed by klfrancisca - Pequenas alterações nas
colisões dos blocos
r58 ([No log message]) committed by ricardo.cunha.mieic - [No log message]
r57 ([No log message]) committed by klfrancisca - [No log message]
r56 ([No log message]) committed by klfrancisca - [No log message]
r55 ([No log message]) committed by klfrancisca - [No log message]
r54 ([No log message]) committed by klfrancisca - [No log message]
r53 ([No log message]) committed by klfrancisca - [No log message]
r52 ([No log message]) committed by klfrancisca - [No log message]
r51 ([No log message]) committed by ricardo.cunha.mieic - [No log message]
r50 ([No log message]) committed by klfrancisca - [No log message]
r49 ([No log message]) committed by ricardo.cunha.mieic - [No log message]
r48 ([No log message]) committed by klfrancisca - [No log message]
r47 (Actualização do Relatorio.doc) committed by ricardo.cunha.mieic - Actualização do Relatorio.doc
26 Maio 2010
r46 ([No log message]) committed by klfrancisca - [No log message]
r45 ([No log message]) committed by klfrancisca - [No log message]
r44 ([No log message]) committed by klfrancisca - [No log message]
r43 ([No log message]) committed by ricardo.cunha.mieic - [No log message]
r42 ([No log message]) committed by ricardo.cunha.mieic - [No log message]
Commits mais antigos
May 25, 2010
r41 (Adicionadas musicas ) committed by ricardo.cunha.mieic - Adicionadas musicas
May 24, 2010
r40 ([No log message]) committed by ricardo.cunha.mieic - [No log message]
May 23, 2010
r39 ([No log message]) committed by klfrancisca - [No log message]
May 23, 2010
r38 (Modificacoes no RTC handler de modo a tocar musica ) committed by ricardo.cunha.mieic Modificacoes no RTC handler de modo a tocar musica
May 23, 2010
r37 ([No log message]) committed by klfrancisca - [No log message]
May 23, 2010
r36 (Modificações básicas nno funcionamento da pilha para os scan...) committed by klfrancisca Modificações básicas nno funcionamento da pilha para os scancodes.
May 21, 2010
r35 ([No log message]) committed by klfrancisca - [No log message]
May 21, 2010
r34 ([No log message]) committed by klfrancisca - [No log message]
May 20, 2010
25
Laboratório de Computadores | T5G03
r33 ([No log message]) committed by klfrancisca - [No log message]
May 20, 2010
r32 ([No log message]) committed by klfrancisca - [No log message]
May 20, 2010
r31 (Melhorado sistema de mostrar pontuações - colisões dos bloco...) committed by ricardo.cunha
May 19, 2010
r30 (Foram incluídas as queues para o movimento da barra.) committed by klfrancisca
r29 ([No log message]) committed by ricardo.cunha.mieic - [No log message]
May 17, 2010
r28 ([No log message]) committed by klfrancisca - [No log message]
May 13, 2010
r27 ([No log message]) committed by ricardo.cunha.mieic - [No log message]
May 11, 2010
r26 ([No log message]) committed by ricardo.cunha.mieic - [No log message]
May 05, 2010
r25 ([No log message]) committed by klfrancisca - [No log message]
May 05, 2010
r24 ([No log message]) committed by klfrancisca - [No log message]
May 05, 2010
r23 ([No log message]) committed by ricardo.cunha.mieic - [No log message]
May 05, 2010
r22 ([No log message]) committed by klfrancisca - [No log message]
May 05, 2010
r21 ([No log message]) committed by klfrancisca - [No log message]
May 04, 2010
r20 (Adicionado createGame() para criar uma nova estrutura do tipo Game) committed by
ricardo.cunha.mieic
Apr 30, 2010
r19 ([No log message]) committed by ricardo.cunha.mieic - [No log message]
Apr 29, 2010
r18 ([No log message]) committed by klfrancisca - [No log message]
Apr 29, 2010
r17 (Adicionado makefile, criado showMenu, process_kbd, showBestS...) committed by
ricardo.cunha.mieic
Apr 28, 2010
r16 ([No log message]) committed by klfrancisca - [No log message]
Apr 28, 2010
r15 ([No log message]) committed by klfrancisca - [No log message]
Apr 28, 2010
r14 ([No log message]) committed by ricardo.cunha.mieic - [No log message]
Apr 28, 2010
r13 ([No log message]) committed by klfrancisca - [No log message]
Apr 24, 2010
r12 (modificado sprite.c, adicionado kbc.c e rtc.c para interrupc...) committed by ricardo.cunha.mieic modificado sprite.c, adicionado kbc.c e rtc.c para interrupcoes do teclado e RTC. Funcao em assembly
kbc_isr, para buscar scancode de uma tecla.
Apr 24, 2010
r11 (modificado sprite.c, adicionado kbc.c e rtc.c para interrupc...) committed by ricardo.cunha.mieic modificado sprite.c, adicionado kbc.c e rtc.c para interrupcoes do teclado e RTC. Funcao em assembly
kbc_isr, para buscar scancode de uma tecla.
Apr 23, 2010
r10 (adicionado Gqueue.c Gqueue.h e pixmap.h para as sprites) committed by ricardo.cunha.mieic adicionado Gqueue.c Gqueue.h e pixmap.h para as sprites
Apr 23, 2010
r9 ([No log message]) committed by ricardo.cunha.mieic - [No log message]
26
Laboratório de Computadores | T5G03
Apr 23, 2010
r8 (Update da proposta de trabalho) committed by ricardo.cunha.mieic - Update da proposta de
trabalho
Apr 22, 2010
r7 ([No log message]) committed by klfrancisca - [No log message]
Apr 22, 2010
r6 ([No log message]) committed by klfrancisca - [No log message]
Apr 22, 2010
r5 ([No log message]) committed by klfrancisca - [No log message]
Apr 22, 2010
r4 ([No log message]) committed by klfrancisca - [No log message]
Apr 22, 2010
r3 ([No log message]) committed by klfrancisca - [No log message]
Apr 14, 2010
r2 (Proposta de trabalho para entregar a 16 de Abril.) committed by klfrancisca - Proposta de trabalho
para entregar a 16 de Abril.
Apr 13, 2010
Project lcomproject created by klfrancisca - Trabalho Práctico LCOM - FEUP - 2009 - 2010
Anexo E – Makefile
LDFLAGS = -g
OBJ = main.o game.o kbc.o kbd_isr.o ints.o sprite.o video-graphics.o
rtc.o time_tick.o timer.o queue.o music.o gqueue.o
all: arkanoid.exe
arkanoid.exe: $(OBJ)
gcc -Wall $(OBJ) -o arkanoid.exe
main.o: main.c game.h rtc.h video-graphics.h
gcc -Wall -c main.c
game.o: game.c game.h utypes.h kbc.h ints.h pixmap.h local_table.h
queue.h
gcc -Wall -c game.c
queue.o: queue.h queue.c utypes.h
gcc -Wall -c queue.c
gqueue.o: gqueue.h gqueue.c utypes.h
gcc -Wall -c gqueue.c
kbc.o: kbc.c kbc.h
gcc -Wall -c kbc.c
music.o: music.c music.h timer.h utypes.h
gcc -Wall -c music.c
timer.o: timer.c timer.h
gcc -Wall -c timer.c
rtc.o: rtc.c rtc.h ints.h utypes.h music.h timer.h
gcc -Wall -c rtc.c
kbd_isr.o: kbd_isr.asm
27
Laboratório de Computadores | T5G03
nasm -t -f coff kbd_isr.asm -o kbd_isr.o
time_tick.o: time_tick.asm
nasm -t -f coff time_tick.asm -o time_tick.o
ints.o: ints.c ints.h
gcc -Wall -c ints.c
sprite.o: sprite.c sprite.h video-graphics.h utypes.h
gcc -Wall -c sprite.c
video-graphics.o: video-graphics.c video-graphics.h
gcc -Wall -c video-graphics.c
clean:
rm -f *.o arkanoid.exe
Anexo F – Proposta inicial
Proposta de Trabalho para Laboratórios de Computadores
2009-2010
Nomes: Francisca Teixeira (090509139) e Ricardo Cunha (080509117)
Turma: 2MIEIC6
Grupo: 3
Link do trabalho: http://code.google.com/p/lcomproject/
Titulo: Arkanoid
Tipo: Bat and ball - Breakout
Baseado em: Jogo com o mesmo nome
Periféricos: Placa gráfica em modo texto e gráfico, teclado, RTC, timer
Interrupções: Teclado, RTC
Funções Assembly: (a preencher na 2ª semana)
Descrição: O jogo é formado por uma bola, uma tabela móvel e blocos coloridos. O
ecrã é limitado superior e lateralmente por paredes indestrutíveis, e aberto
inferiormente. Os blocos encontram-se agregados na zona superior do ecrã. O jogador
tem controlo apenas sobre a tabela móvel (na direcção horizontal), devendo utilizá-la
para evitar que a bola, que se encontra em constante movimento horizontal e vertical
desde o ínicio do jogo, caia no limite inferior (aberto) do ecrã, desaparecendo. Caso
não consiga evitá-lo, perderá uma das três hipóteses (vidas) que dispõe.
A bola, por sua vez, ao bater num bloco destrói-o, fazendo-o desaparecer. Cada vez
que esta embata numa parede, bloco ou na tabela móvel, mudará de direcção. O
jogador somará pontos por cada bloco destruído.
Durante a realização do jogo o tempo corrente do mesmo é mostrado, assim como o
28
Laboratório de Computadores | T5G03
número de blocos destruídos e o número de vidas restantes.
Para passar ao nível seguinte, o jogador deve eliminar todos os blocos coloridos do
nível em que se encontra. Subindo de nível, a velocidade da bola aumenta, tornandose mais difícil o controlo desta.
Planeamento: (a preencher na 2ª semana. Deve incluir protótipo de funções a
implementar. Se não for desde já possível incluir protótipos das funções a implementar
em cada semana, fazê-lo só para a 1ª semana, e apresentar em cada aula os
protótipos das funções a implementar na semana seguinte)
1ª semana: Os objectivos para esta semana consistem em: criar sprites, animar
sprites, limpar sprites do ecrã e verificar colisões com as paredes. Protótipos a
implementar:
Sprite* create_sprite(char* pic, char* base, int x, int y);
Int animate_sprite(Sprite* fig, char* base);
void destroy_sprite(Sprite* fig, char* base);
int checkColision(Sprite* fig, int x, int y);
2ª semana: Nesta semana comprometemo-nos a criar o ambiente gráfico do jogo e
torná-lo navegável, ou seja, menu inicial, menu de instrucções, menu de melhores
pontuações e ambiente de acção do jogo. Protótipos:
void startMenu(char* base);
void showInstructions(char* base)
void showBestScores(char* base);
void process_kbd(char* base);
void startGame(char* base);
3ª semana: Os objectivo passam por:
-
Modificar a rotina void kbd_handler() para guardar os scancodes do teclado
numa queue, de forma a processar eficientemente o movimento da tabela no
ambiente do jogo.
-
Desenvolver a função Sprite *** createBlocks(char* base, int nrows, int ncol),
que cria e devolve um apontador para uma estrutura que contém os blocos a
serem desenhados na cena e posteriormente destruídos.
-
Terminar o desenvolvimento da função void startGame(char* base, char*
baseTmp, Game* game), para que seja possível jogar efectivamente, isto é,
processar o devido comportamento da bola quando embate na tabela, paredes
indestrutíveis que compõem a cena do jogo e blocos.
-
Activar outras pequenas funcionalidades como a contagem de vidas que o
jogador possui, pontos por jogo e no total, best-score, etc.
29
Download

ARKANOID