Desenvolvimento de jogos/Programação Megadrive
Introdução
Este wikibook destina-se àqueles que estejam interessados no desenvolvimento de jogos para o videogame conhecido como Mega Drive.
(Em construção)
Ferramentas
Montadores
Também conhecidos pelo termo inglês assemblers, geram o código de máquina referente ao código fonte escrito na linguagem de montagem (assembly). No caso do Mega Drive, o código é escrito para os processadores Motorola 68000 (também conhecido como M68k ou M68000) e Z80, da Zilog, sendo o Z80 um coprocessador de áudio e para "compatibilidade" com jogos de Master System.
GAS
O GNU Assembler (GAS) [1]. Ele é bem completo, pleno de recursos e genérico quanto a processador. Sua sintaxe segue o padrão AT&T em vez do da Intel. Caso seja necessário compilar o GAS para o M68k, utilize os seguintes comandos:
./configure -target=m68k-coff make
O primeiro comando configura o alvo de montagem ser o processador família M68k, sem sistema operacional. O segundo efetivamente compila os programas componentes do GAS, que são:
- addr2line
- ar
- as
- cxxfilt
- ld
- nm
- objcopy
- objdump
- ranlib
- readelf
- size
- strings
- strip
Os mais usados, para fins de programas para Mega Drive, são o as (o montador/assembler), o ld (o ligador/linker) e o objcopy (para gerar o arquivo no formato binário correto).
Usando o as
as -m68000 -o arquivo.o arquivo.s
É importante o uso do parâmetro -m68000, porque o padrão é 68020. O parâmetro -o serve para definir o nome do arquivo objeto de saída (o padrão é "a.out"). Por fim, o não opcional: o código-fonte.
Usando o ld
Após feita as compilações de todas os códigos do programa, é preciso ligá-los.
ld --oformat=binary -Ttext=0 -o rom.bin arquivo.o [outros .o]
- --oformat=binary e -Ttext=0 são necessários para o correto formato do arquivo binário.
- -o, como já mencionado para o as, define o nome do arquivo binário de saída, no caso "rom.bin"
- O parâmetro obrigatório para o ld é, obviamente, o(s) arquivo(s) objeto(s) que compõe o programa.
Compiladores
BasiEgaXorz
Compilador de BASIC para Mega Drive, muito fácil de usar, e vem com muitos exemplos.
Pode ser baixado neste site
SGCC - Sega Genesis C Compiler
Compilador de C para Mega Drive. Embora tenha alguns problemas, como o fato de usar um dialeto arcaico da linguagem C, (Sintaxe K&R, para ser mais exato), ele é extremamente simples de usar, bastando descompactar e usar, além de já vir com alguns exemplos simples.
Pode ser baixado deste site, ou deste
GCC68k - GNU C Compiler for 68k
Versão do GNU C adaptado para o processador MC68000. Suporta tanto C como C++, podendo também suportar outras linguagens, como Fortran, Pascal e outros, dependendo da configuração. Tem a desvantagem de ser ligeiramente mais difícil de usar do que o SGCC.
Neste site, você pode baixar uma versão deste compilador já preparada para o Mega Drive.
Conversores de imagens
Básico
Para os exemplos desta seção, será utilizado o BasiEgaXorz, por ser mais simples de usar.
Escrevendo texto na tela
Usando o BasiEgaXorz, esta tarefa se torna bastante simples:
print "Ola, mundo!!!"
Definindo a palheta de cores
O Megadrive possui quatro palhetas de cores, cada uma com 16 cores, selecionáveis dentre 512.
O BasiEgaXorz possui dois comandos para setar as palhetas do Megadrive:
PALLETTE seta uma única cor de uma única palheta. A sua sintaxe é:
Pallette <código RGB>, <n° da palheta>, <n° da cor>
- <código RGB> é um número hexadecimal que repesenta os tons de vermelho, verde e azul que compõem a cor desejada. Para calcular o código equivalente à cor, utilize a fórmula (R*2)+(G*32)+(B*512), onde:
- R representa o tom de vermelho, entre 0 e 7
- G representa o tom de verde, entre 0 e 7
- B representa o tom de azul, entre 0 e 7
- <n° da palheta> indica o número da palheta que se deseja modificar
- <n° da cor> indica qual das cores desta palheta será alterada
Exemplo:
ink 0 print "Texto usando a palheta0" ink 1 print "Texto usando a palheta1" ink 2 print "Texto usando a palheta2" ink 3 print "Texto usando a palheta3" ' ink 0 print print "Pressione qualquer botao..." while joypad()=0: wend waitpadup 0 ' pallette 14, 0, 1 pallette 224, 1, 1 pallette 3584, 2, 1 pallette 238, 3, 1 ' ink 1 print "Observe como a cor do texto mudou ao" print "alterar a palheta"
O exemplo acima imprime uma linha de texto com cada palheta, espera o usuário pressionar qualquer botão do joystick, e então altera a cor 1 de cada palheta, a qual corresponde à cor utilizada pelo texto; como consequência, o texto muda de cor.
PALLETTES pode setar várias cores de uma determinada palheta de uma só vez. A sua sintaxe é:
Pallettes <rótulo dos dados>, <n° da palheta>, <cor inicial>, <n° de cores>, [Deslocamento]
- <rótulo dos dados> indica qual rótulo de dados será lido para definir as cores da palheta indicada (veja o exemplo abaixo para entender melhor)
- <n° da palheta> número da palheta que será alterada
- <cor inicial> cor inicial a ser alterada. Por exemplo, se a cor inicial for 4 e o número de cores for 3, serão alteradas as cores 4, 5 e 6
- <n° de cores> o número de cores que serão alteradas
- [Deslocamento] parâmetro opcional que indica a posição dentro dos dados indicados pelo rótulo a partir da qual os dados serão lidos.
Exemplo:
ink 0 print "Texto usando a palheta0" ink 1 print "Texto usando a palheta1" ink 2 print "Texto usando a palheta2" ink 3 print "Texto usando a palheta3" ' ink 0 print print "Pressione qualquer botao..." while joypad()=0: wend waitpadup 0 ' pallettes pallette1, 0, 0, 16 pallettes pallette2, 1, 0, 16 pallettes pallette3, 2, 0, 16 pallettes pallette4, 3, 0, 16 ' ink 1 print "Observe como a cor do texto mudou ao" print "alterar a palheta, assim como a cor" print "do fundo." ' pallette1: DATAINT $0ECA,$00EE,$0EA8,$0CA6,$0CAC,$08CA,$08AA,$0A68 DATAINT $0866,$0ACE,$0442,$0686,$066A,$0AAE,$06AA,$0000 pallette2: DATAINT $0002,$00AA,$002A,$004A,$006E,$02AE,$002C,$04AE DATAINT $02EE,$04EE,$0046,$0468,$04AA,$028A,$08CC,$0000 pallette3: DATAINT $0620,$0088,$0A62,$0CEC,$0644,$0CA4,$0684,$06A8 DATAINT $0868,$0424,$0444,$0222,$0648,$0428,$0000,$0000 pallette4: DATAINT $0422,$0044,$0426,$0446,$086A,$0CEE,$044A,$0866 DATAINT $06AE,$0642,$0202,$0244,$0662,$0000,$0000,$0000
No exemplo acima, pallette1, palette2, palette3 e palette4 são rótulos que apontam para dados, os quais, neste caso, são definidos pelo comando DATAINT. O cifrão na frente de cada número serve para indicar que o número em questão está em notação hexadecimal. Isso torna mais fácil visualizar a cor que está sendo definida, visto que os três últimos dígitos do código da cor em hexa correspondem justamente aos valores de azul, verde e vermelho, respectivamente. Observe, também, que a cor do fundo também foi alterada, porque a cor zero da palheta zero também mudou.
Importante: Se for copiar e colar este exemplo para o BasiEgaXorz, lembre-se de tirar o espaço à esquerda dos rótulos, mas apenas dos rótulos. Isto é necessário, porque o BasiEgaXorz pressupõe que qualquer linha que comece com um ou mais espaços à esquerda não contenha um rótulo.
Lendo o joystick
Existem algumas funções para o BasiEgaXorz que fazem o software interagir com o joystick, vou lista-las primeiramente, e a seguir dou um exemplo mais prático.
WaitPadUp <# do controle>
Espera que o device do numero especificado seja ligado ao console. Você pode fazer o jogo pausar se o controle for removido, ou caso o jogador selecione a opção de 2 players, verificar a existencia de um segundo controle para prosseguir.
Importante: os valores para o primeiro e o segundo controle são 0 e 1 respectivamente.
Joypad(<# do controle>)
Essa função de longe é a mais importante para interação com o controle. Essa função retorna o bit do evento correspondente. A tabela a baixo mostra a relação de Bit-Evento.
Bit Hex Decimal Evento 0 &h001 1 Cima 1 &h002 2 Baixo 2 &h004 4 Esquerda 3 &h008 8 Direita 4 &h010 16 B 5 &h020 32 C 6 &h040 64 A 7 &h080 128 Start 8 &h100 256 Z (6-Botões) 9 &h200 512 Y (6-Botões) 10 &h400 1024 X (6-Botões) 11 &h800 2048 Mode (6-Botões)
Não vou entrar muito em detalhes, vocês podem procurar no site da BasiEgaXorz por uma documentação mais detalhada, mas quando se utiliza joystick de 3 botoes os bits referentes aos botões ZYX não estarão 'limpos', e sim tera um valor randomico qualquer, I.E, lixo. Tomar cuidado com isso.
Vamos ao exemplo:
Cole o exemplo abaixo no BasiEgaXorz, lembrando que deve haver um espaço em branco antes de cada comando. Reparem que foi utilizado joypad() sem nenhum parâmetro, caso este esteja omitido o padrão é o primeiro controle.
WaitPadUp 'se omitir o valor 0 ou 1, será o valor padrao é 0 Print "Controle 1 esta conectado" ' Player Joypad Inputs while 1 sleep 5 'so para nao ficar num loop frenetico e ocupar muito a cpu joy = joypad() 'mesma coisa que no waitpadup if joy.0 then ' cima Print "cima" endif if joy.1 then ' baixo Print "baixo" endif if joy.2 then ' esquerda Print "esquerda" endif if joy.3 then ' direita Print "direita" endif if joy.4 then ' b Print "b" endif if joy.5 then ' c Print "c" endif if joy.6 then ' a Print "a" endif if joy.7 then ' start Print "start" endif if joy.8 then ' z Print "z" endif if joy.9 then ' y Print "y" endif if joy.10 then ' x Print "x" endif if joy.11 then 'mode 6 button Print "mode 6 button" endif 'voce tambem pode usar capturar mais de um envento ao mesmo tempo, por exemplo. 'perceba que ele caira em todos os if's no do botao B, no do botao C, e no BC. 'se quizer aninhar os ifs - else, pode facilmente impedir isso. 'Nao fiz pois achei que ficaria mais claro os exemplos assim. if joy.4 and joy.5 then print "bc" endif wend
O ideal é utilizar select-case, ao invés de estrutura if-else por questões de desempenho, além de produzir uma melhor legibilidade ao código. No caso do select utilize os valores decimais da tabela. Caso queiram capturar dois botoes por exemplo, some os valores. Um exemplo com as 4 diagonais.
JOY = JOYPAD() SELECT CASE JOY CASE 1: PRINT "CIMA" EXIT CASE CASE 2: PRINT "BAIXO" EXIT CASE CASE 4: PRINT "ESQUERDA" EXIT CASE CASE 5: PRINT "DIAGONAL ESQUERDA PRA CIMA" EXIT CASE CASE 6: PRINT "DIAGONAL ESQUERDA PRA BAIXO" EXIT CASE CASE 8: PRINT "DIREITA" EXIT CASE CASE 9: PRINT "DIAGONAL DIREITA PRA CIMA" EXIT CASE CASE 10: PRINT "DIAGONAL DIREITA PRA BAIXO" EXIT CASE
Movendo objetos pela tela
Exibindo uma imagem no fundo da tela
Seu primeiro jogo: Como fazer um clone do "Pong"
Fazendo a bola ricochetear pela tela
Checagem de colisão: Rebatendo a bola
Marcando a pontuação
Inteligência artificial básica: Jogador 1 versus CPU
Múltiplos inimigos na tela: Fazendo seu próprio Galaxian
Intermediário
Visão geral do hardware do Mega Drive
Movimentando os planos de fundo
Som básico: Usando o PSG
Avançado
Descrição das portas de I/O do Mega Drive
VDP
$C00000 (Porta de dados)
$C00004 (Porta de controle)
Leitura
* | * | * | * | * | * | VAZIO | CHEIO |
F | SOVR | C | IMPAR | VB | HB | PAL |
VAZIO 1: FIFO de escrita vazio 0: CHEIO 1: FIFO de escrita cheio 0: F 1: Ocorreu interrupção vertical SOVR 1: Ocorreu estouro de sprites. Muitos na mesma linha. Mais de 17 no modo de 32 células. Mais de 21 no modo de 40 células. C 1: Ocorreu colisão entre dois pixels não nulos entre dois sprites. 0: IMPAR 1: Quadro ímpar no modo entrelaçado. 0: Quadro par no modo entrelaçado. VB 1: Durante o "blanking" vertical 0: HB 1: Durante o "blanking" horizontal 0: DMA 1: Realizando DMA 0: PAL 1: Modo PAL 0: Modo NTSC
Escrita 1: Enviar dados ao registrador
1 | 0 | 0 | RS4 | RS3 | RS2 | RS1 | RS0 |
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
RS4 ~ RS0 : Número do registrador D7 ~ D0 : Dados a enviar
- As portas do VDP devem ser acessadas via "word" ou "long word", para correto funcionamento.
Escrita 2: Seleção de endereço
1ª Escrita
CD1 | CD0 | A13 | A12 | A11 | A10 | A9 | A8 |
A7 | A6 | A5 | A4 | A3 | A2 | A1 | A0 |
2ª Escrita
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
CD5 | CD4 | CD3 | CD2 | 0 | 0 | A15 | A14 |
CD5 ~ CD0 : Código de indentificação A15 ~ A0 : Endereço de destino
Modo de Acesso | CD5 | CD4 | CD3 | CD2 | CD1 | CD0 |
Escrita em VRAM | 0 | 0 | 0 | 0 | 0 | 1 |
Escrita em CRAM | 0 | 0 | 0 | 0 | 1 | 1 |
Escrita em VSRAM | 0 | 0 | 0 | 1 | 0 | 1 |
Leitura da VRAM | 0 | 0 | 0 | 0 | 0 | 0 |
Leitura da CRAM | 0 | 0 | 1 | 0 | 0 | 0 |
Leitura da VSRAM | 0 | 0 | 0 | 1 | 0 | 0 |
$C00008 (Contador horizontal/vertical)
Modo não entrelaçado
VC7 | VC6 | VC5 | VC4 | VC3 | VC2 | VC1 | VC0 |
HC8 | HC7 | HC6 | HC5 | HC4 | HC3 | HC2 | HC1 |
Modo entrelaçado
VC7 | VC6 | VC5 | VC4 | VC3 | VC2 | VC1 | VC8 |
HC8 | HC7 | HC6 | HC5 | HC4 | HC3 | HC2 | HC1 |
HC8 ~ HC1 : Posição horizontal VC8 ~ VC0 : Posição vertical
Registradores
REG 0: Registrador de modo número 1
0 | 0 | 0 | IE1 | 0 | 1 | M3 | 0 |
IE1 1: Habilita interrupção horizontal (68000 nível 4) 0: Desabilita interrupção horizontal (REG #10) M3 1: Parar o contador HV 0: Habilita o contador HV para leitura
REG 1: Registrador de modo número 2
0 | DISP | IE0 | M1 | M2 | 1 | 0 | 0 |
DISP 1: Habilita display 0: Desabilita display IE0 1: Habilita interrupção vertical (68000 nível 6) 0: Desabilita interrupção vertical M1 1: Habilita DMA 0: Desabilita DMA M2 1: Modo 30 células na horizontal (modo PAL) 0: Modo 28 células na horizontal (Modo PAL, sempre 0 em modo NTSC)
REG 2: Endereço base do mapa do fundo A
0 | 0 | SA15 | SA14 | SA13 | 0 | 0 | 0 |
Endereço da VRAM: $XXX0_0000_0000_0000
REG 3: Endereço base do mapa da janela
0 | 0 | WD15 | WD14 | WD13 | WD12 | WD11 | 0 |
WD11 deve ser 0 no modo de 40 células horizontais Endereço da VRAM: $XXXX_X000_0000_0000 (32 células horizontais) Endereço da VRAM: $XXXX_0000_0000_0000 (40 células horizontais)
REG 4: Endereço base do mapa do fundo B
0 | 0 | 0 | 0 | 0 | SB15 | SB14 | SB13 |
Endereço da VRAM: $XXX0_0000_0000_0000
REG 5: Endereço base da tabela de atributos dos sprites
0 | AT15 | AT14 | AT13 | AT12 | AT11 | AT10 | AT9 |
WD9 deve ser 0 no modo de 40 células horizontais Endereço da VRAM: $XXXX_XXX0_0000_0000 (32 células horizontais) Endereço da VRAM: $XXXX_XX00_0000_0000 (40 células horizontais)
REG 7: Cor do fundo
0 | 0 | CPT1 | CPT0 | COL3 | COL2 | COL1 | COL0 |
CPT1 ~ CPT0 : Número da palheta COL3 ~ COL0 : Código da cor
REG 10: Interrupção horizontal
BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0 |
Conta o número da linha horizontal da tela sendo atualmente renderizado
REG 11: Registrador de modo número 3
0 | 0 | 0 | 0 | IE2 | VSCR | HSCR | LSCR |
IE2 1: Habilita interrupção externa (68000 nível 2) 0: Desabilita interrupção externa
Modo de deslocamento horizontal
VSCR | Função |
0 | Scroll completo |
1 | Scroll a cada duas células |
Modo de deslocamento vertical
HSCR | LSCR | Função |
0 | 0 | Scroll completo |
0 | 1 | Inválido |
1 | 0 | Scroll célula a célula |
1 | 1 | Scroll linha a linha |
REG 12: Registrador de modo número 4
RS0 | 0 | 0 | 0 | S/TE | LSM1 | LSM0 | RS1 |
RS0 0: Modo de 32 células horizontais 1: Modo de 40 células horizontais RS1 0: Modo de 32 células horizontais 1: Modo de 40 células horizontais * É recomendável setar o mesmo valor para RS0 e RS1. S/TE 1: Habilita sombreamento e realce 0: Habilita sombreamento e realce LSM1, LSM0: Modo de entrelaçamento
LSM1 | LSM2 | Função |
0 | 0 | Sem entrelaçamento |
0 | 1 | Entrelaçado |
1 | 0 | Inválido |
1 | 1 | Entrelaçado (Dupla resolução) |
REG 13: Endereço da tabela de deslocamento horizontal
0 | 0 | HS15 | HS14 | HS13 | HS12 | HS11 | HS10 |
Endereço da VRAM: $XXXX_XX00_0000_0000
REG 15: Dados de auto incremento
A cada vez que a CPU acessa a memória da VDP do Mega Drive, a posição atual desta memória é incrementada. Este registrador define o tamanho do incremento.
0 | 0 | HS15 | HS14 | HS13 | HS12 | HS11 | HS10 |
INC7 ~ INC0: Tamanho do incremento ( 0 ~ $FF )
REG 16: Tamanho do plano de fundo
0 | 0 | VSZ1 | VSZ0 | 0 | 0 | HSZ1 | HSZ0 |
VSZ1 | VSZ0 | Função |
0 | 0 | 32 células na vertical |
0 | 1 | 64 células na vertical |
1 | 0 | Inválido |
1 | 1 | 128 células na vertical |
HSZ1 | HSZ0 | Função |
0 | 0 | 32 células na horizontal |
0 | 1 | 64 células na horizontal |
1 | 0 | Inválido |
1 | 1 | 128 células na horizontal |
REG 17: Posição horizontal da janela
RIGT | 0 | 0 | WHP5 | WHP4 | WHP3 | WHP2 | WHP1 |
RIGT 0: Janela está à esquerda do ponto base 1: Janela está à direita do ponto base WHP5 ~ WHP1 Posição horizontal em células, isto é de 8 em 8 pixels
REG 18: Posição vertical da janela
DOWN | 0 | 0 | WVP4 | WVP3 | WVP2 | WVP1 | WVP0 |
DOWN 0 : Janela está acima do ponto base 1 : Janela está abaixo do ponto base WVP4 ~ WVP0 Posição vertical em células
REG 19: Byte menos significativo do contador de DMA
LG7 | LG6 | LG5 | LG4 | LG3 | LG2 | LG1 | LG0 |
REG 20: Byte mais significativo do contador de DMA
LG15 | LG14 | LG13 | LG12 | LG11 | LG10 | LG9 | LG8 |
REG 21: Porção inferior do endereço de origem de DMA
SA8 | SA7 | SA6 | SA5 | SA4 | SA3 | SA2 | SA1 |
REG 22: Porção central do endereço de origem de DMA
SA16 | SA15 | SA14 | SA13 | SA12 | SA11 | SA10 | SA9 |
REG 23: Porção superior do endereço de origem de DMA
DMD1 | DMD0 | SA22 | SA21 | SA20 | SA19 | SA18 | SA17 |
SA22 ~ SA1 : Endereço de origem de DMA DMD1, DMD0 : Modo de DMA
DMD1 | DMD0 | Função |
0 | SA23 | Memória para vídeo |
1 | 0 | Preenche VRAM |
1 | 1 | Vídeo para vídeo |
Exemplo de utilização das portas
void init_GFX() { register unsigned int *pw; pw = (uint *) 0xC00004; /* Aponta para a porta de controle */ *pw = 0x8016; /* reg. 0 - Habilita HBL */ *pw = 0x8174; /* reg. 1 - Habilita display, VBL, DMA e seta a largura */ *pw = 0x8230; /* reg. 2 - Plano A =$30*$400=$C000 */ *pw = 0x832C; /* reg. 3 - Janela =$2C*$400=$B000 */ *pw = 0x8407; /* reg. 4 - Plano B =$7*$2000=$E000 */ *pw = 0x855E; /* reg. 5 - Tabela de sprites em $BC00=$5E*$200 */ *pw = 0x8700; /* reg. 7 - Cor do fundo */ *pw = 0x8a01; /* reg 10 - HInterrupt timing */ *pw = 0x8b00; /* reg 11 - $0000abcd a=interrupção externa b=scroll horiz. cd=scroll vert. */ *pw = 0x8c81; /* reg 12 - células horiz + sombreamento/realce + modo entrelaçamento (40 células, sem sombreamento, sem entrelaçamento)*/ *pw = 0x8d2E; /* reg 13 - Tabela de deslocamento horizontal = $B800 */ *pw = 0x8f02; /* reg 15 - auto incremento */ *pw = 0x9011; /* reg 16 - tamanho dos planos de fundo (64x64) */ *pw = 0x9100; /* reg 17 - posição horizontal da janela */ *pw = 0x92ff; /* reg 18 - posição vertical da janela */ };
Programação assembly 68k
Documentação Assembly
A extensa documentação do assembly do 68k pode ser encontrada no Devega.
Cabeçalho da ROM
O cabeçalho da ROM para Mega Drive consiste de duas seções, cada uma de 256 bytes. A primeira é "exigida" pelo processador, e indicam o início da pilha, o endereço da rotina principal e os endereços das rotinas de exceções (traps) e interrupções. Já a segunda seção é uma padronização realizada pela SEGA para identificação do cartucho (direitos autorais, nome do produto, etc.) e informações sobre utilização de recursos do hardware (mapeamento de memória, periféricos, etc.).
Item | Endereço | Descrição |
---|---|---|
1 | 0x000000 | Endereço do início da pilha (geralmente próximo ao fim da memória RAM) |
2 | 0x000004 | Endereço da rotina principal (valor inicial do PC, também para quando resetado) |
26 | 0x000068 | Interrupção de nível 2: no Mega Drive, Externa. |
28 | 0x000070 | Interrupção de nível 4: no Mega Drive, Retraço Horizontal. |
30 | 0x000078 | Interrupção de nível 6: no Mega Drive, Retraço Vertical. |
O conteúdo de cada elemento do Vetor de Exceções é o endereço absoluto (em relação ao primeiro byte do arquivo binário) da respectiva rotina de tratamento da exceção. Cada elemento consiste de 4 bytes.
O costume é, quando for desejado não tratar certas exceções, elas reiniciem o software, ou seja, apontem para o começo do programa. Vale destacar que as interrupções de retraço devem ser tratadas, nem que seja não fazer nada, já que são efetivamente geradas a tempo constante.
As demais exceções/interrupções não citadas podem ser encontradas no Apêndice B do MOTOROLA M68000 FAMILY Programmer's Reference Manual disponível no Devega.