Baixe o app para aproveitar ainda mais
Prévia do material em texto
game program™ PROGRAMAÇÃO PARA ATARI 2600 Use with Joystick Controllers Proposta Entender o que torna o Atari tão diferente de outros sistemas, aprendendo o básico para escrever um “Hello, World” e poder apreciar clássicos como Enduro ou Pitfall! pela habilidade de seus criadores http://slideshare.net/chesterbr http://slideshare.net/chesterbr Palestrante @chesterbr http://chester.me http://chester.me/ Palestrante @chesterbr http://chester.me http://chester.me/ Atari 2600 (Video Computer System) Mais de 600 jogos... imagem: mitchelaneous.com mas por que eram tão... “Atari”? Por dentro do Atari (Jr.) Fotos: Larry Ziegler (2600 CE) CPU: 6507 Fotos: Larry Ziegler (2600 CE) CPU: 6507 Fotos: Larry Ziegler (2600 CE) 6502 Video: TIA Fotos: Larry Ziegler (2600 CE) Todo o resto: RIOT (6532) Fotos: Larry Ziegler (2600 CE) Mapa da Memória 0000-002C – TIA (Escrita) 0030-003D – TIA (Leitura) 0080-00FF – RIOT (RAM) 0280-0297 – RIOT (I/O, Timer) F000-FFFF – Cartucho (ROM) Mapa da Memória F000-FFFF – Cartucho (ROM) esse nem é o maior problema... 4 KBytes! Mapa da Memória 0080-00FF – RIOT (RAM) e esse ainda não é o maior problema... 128 BYTES!!!!! (1/8 de KB) VRAM Um chip de vídeo típico transforma padrões de bits armazenados em memória (VRAM) em pixels e cores VRAMVRAM VRAM 38 44 44 7C 44 44 EE 00 VRAM Quanto mais memória (VRAM), maior a resolução, e variedade de cores. Memória era cara nos anos 70/80, levando a um tradeoff. Quanta VRAM o Atari tem? Mapa da Memória 0000-002C – TIA (Escrita) 0030-003D – TIA (Leitura) 0080-00FF – RIOT (RAM) 0280-0297 – RIOT (I/O, Timer) F000-FFFF – Cartucho (ROM) Mapa da Memória ????-???? – VRAM Mapa da Memória 0 bytes !!!! ????-???? – VRAM #comofas? TIA (Television Interface Adaptor) Funcionamento da TV Fonte: How Stuff Works Funcionamento da TV Fonte: How Stuff Works Scanlines Fonte: How Stuff Works 60 quadros (frames) por segundo TIA opera em scanlines Para cada scanline, você escreve em posições de memória do TIA que configuram “objetos desenháveis” É difícil mudar a cor/forma de um objeto numa mesma scanline Isso explica vs. E que objetos são esses? ● Playfield (PF) ● Players (P0, P1) ● Missiles/Ball (M0, M1, BL) Playfield Um padrão de 20 bits (representando cor de frente e cor de fundo) que ocupa o lado esquerdo da scanline. O lado direito repete o mesmo padrão, ou, opcionalmente, uma versão “espelhada” dele PLAYFIELD PLAYFIELD PLAYFIELD PLAYFIELD Configurando o playfield PF0 = 0000 ←← leitura PF1 = 00000000 leitura →→ PF2 = 00000000 ←← leitura REFLECT = 0 scanline resultante ████████████████████████████████████████ Configurando o playfield PF0 = 0001 ←← leitura PF1 = 00000000 leitura →→ PF2 = 00000000 ←← leitura REFLECT = 0 scanline resultante ████████████████████████████████████████ Configurando o playfield PF0 = 0011 ←← leitura PF1 = 00000000 leitura →→ PF2 = 00000000 ←← leitura REFLECT = 0 scanline resultante ████████████████████████████████████████ Configurando o playfield PF0 = 0111 ←← leitura PF1 = 00000000 leitura →→ PF2 = 00000000 ←← leitura REFLECT = 0 scanline resultante ████████████████████████████████████████ Configurando o playfield PF0 = 1111 ←← leitura PF1 = 11110000 leitura →→ PF2 = 00000000 ←← leitura REFLECT = 0 scanline resultante ████████████████████████████████████████ Configurando o playfield PF0 = 1111 ←← leitura PF1 = 11111110 leitura →→ PF2 = 00010101 ←← leitura REFLECT = 0 scanline resultante ████████████████████████████████████████ Configurando o playfield PF0 = 1111 ←← leitura PF1 = 11111110 leitura →→ PF2 = 00010101 ←← leitura REFLECT = 1 scanline resultante ████████████████████████████████████████ Players Cada um dos players é um padrão de 8 bits com sua própria cor Ex.: 10100001 → ████████ Os dois padrões (GRP0/GRP1) podem aparecer na mesma scanline PLAYERS PLAYERS Players É possível esticar/multiplicar e inverter o desenho de cada player usando os registradores NUSIZn e REFPn (n=0 ou 1) NUSIZn (em 5 scanlines) 000 001 010 011 100 101 110 111 N U SI Z n Ligando o REFPn 000 001 010 011 100 101 110 111 N U SI Z n NUSIZn NUSIZn NUSIZn NUSIZn 8 bits exigem criatividade vs. Missiles/Ball Cada um representa um pixel na scanline, mas pode ter sua largura ampliada em 2, 4 ou 8 vezes. Os missiles têm as cores dos players, enquanto ball tem a cor do playfield. MISSILES BALL BALL MISSILE BALL MISSILE Idéia geral Para cada scanline, você configura o formato dos objetos (playfield, players, missiles/ball) e as cores/efeitos deles. O que você configura em uma scanline vale para as seguintes, mas ainda assim o tempo é um problema Contas de padaria: 6502 ≈ 1,19Mhz (1.194.720 ciclos/seg) NTSC: 60 frames (telas) por seg 1.194.720/60 ≅ 19.912 ciclos por tela Contas de padaria: CPU: 19.912 ciclos por tela NTSC: 262 scanlines por frame 19.912 / 262 = 76 ciclos por scanline Contas de padaria: CPU: 19.912 ciclos por tela NTSC: 262 scanlines por frame 19.912 / 262 = 76 ciclos por scanline e o que se faz com “76 ciclos”? (aliás, o que exatamente é um “ciclo”?) Assembly 6502 6502 6502 (no Atari) Executa instruções armazenadas na ROM que manipulam e transferem bytes entre o RIOT (RAM + I/O + timers) e o TIA, com o apoio de registradores internos. Instruções Cada instrução é composta por um opcode (1 byte) seguido por um parâmetro (0 a 2 bytes) Dependendo do opcode, a instrução leva de 2 a 6 ciclos para ser executada Registradores do 6502 A = Acumulador (8 bits) X, Y= Índices (8 bits) S = Stack Pointer (8 bits) P = Status (flags, 8 bits) PC = Program Counter (16 bits) Exemplo de Programa ● Ler o byte da posição de memória 0x0200 para o acumulador (A) ● Somar 1 (um) no A ● Guardar o resultado (A) na posição de memória 0x0201 Código de Máquina 6502 AD Opcode (Memória→A) 00 2a. Parte de “0200” 02 1a. Parte de “0200” 69 Opcode (valor+A→A) 01 valor “01” 8D Opcode (A→Memória) 01 2a. Parte de “0201” 02 1a. Parte de “0201” Linguagem Assembly Atribui a cada opcode uma sigla (“mnemônico”) e define uma notação para os parâmetros Código de Máquina 6502 AD Opcode (Memória→A) 00 2a. Parte de “0200” 02 1a. Parte de “0200” 69 Opcode (valor+A→A) 01 valor “01” 8D Opcode (A→Memória) 01 2a. Parte de “0201” 02 1a. Parte de “0201” Assembly 6502 AD LDA $0200 00 02 69 ADC #01 01 8D STA $0201 01 02 Assembler (Montador) Programa que lê um arquivo-texto escrito em linguagem Assembly e monta o arquivo binário (código de máquina) correspondente foo.asm LDA $0200 ADC #01 STA $0201 ... foo.bin AD000269 018D0102 ... ASSEMBLER DASM ● Macro Assembler 6502 ● Inclui headers para Atari ● Multiplataforma ● Livre (GPLv2) http://dasm-dillon.sourceforge.net/ http://dasm-dillon.sourceforge.net/ Notação (para hoje) #... = valor absoluto $... = endereço, em hexa $..., X = endereço + X, em hexa #$... = valor absoluto em hexa http://www.obelisk.demon.co.uk/6502/addressing.html http://www.obelisk.demon.co.uk/6502/addressing.html Instruções do 6502 = mais relevantes para o Atari Transferindo Dados LDA, LDX, LDY = Load STA, STX, STY = Store TAX, TAY, TXA, TYA, TSX, TXS = Transfer LDA #$10 0x10→A STY $0200 Y→m(0x0200) TXA X→A Aritmética ADC, SBC = +,- (C=“vai um”) INC, DEC = ++,-- (memória) INX, INY, DEX, DEY = ++,-- ADC $0100 m(0x100)+A→A INC $0200 m(0x200)+1→ m(0x200) DEX X-1→X Operações em Bits AND, ORA, EOR = and, or, xor (A) ASL, LSR = Shift aritmético/lógico ROL, ROR = Shift “rotacional” AND #$11 A&0x11→ALSR A>>1→A (A/2→A) ROR A>>1 (bit 7=carry) Comparações e Desvios CMP, CPX, CPY = compara A/X/Y (-) BCS, BCC = desvia se Carry/Não BEQ, BNE = desvia se Equal/Não BVS, BVC = desvia se Overflow/Não BMI, BPL = desvia se Minus/Plus CPY $1234 se y=m(0x1234), BEQ $0200 0x0200→PC Pilha e Subrotinas JSR, RTS = chama subrotina/retorna PHA, PLA = push/pop(pull) do A PHP, PLP = push/pop do status (P) JMP $1234 0x1234→PC JSR $1234 PC(+3)→pilha, 0x1234→PC RTS pilha→PC O Resto... NOP = No Operation (nada!) JMP = Desvio direto (GOTO) SEC, CLC = Set/Clear Carry SEV, CLV = Set/Clear oVerflow SEI, CLI = Set/Clear Interrupt-off SED, CLD = Set/Clear Decimal RTI = Return from Interrupt BRK = Break Neo: “I know kung fu.” Morpheus: “Show me.” © 1999 Warner Bros Hello, World! Hello, World! Escrever na horizontal é complicado (muitos pixels/elementos por scanline) Hello, World! É mais fácil escrever na vertical → (menos pixels/scanline) Podemos usar um player ou o playfield Display kernel É a parte do programa que roda quando o canhão está desenhando a tela propriamente dita (através do playfield, players e missiles/ball) Fonte: Stella Programmers Guide, Steve Wright, 1979 LÓ G IC A D O JO G O (3 + 37 + 30 ).7 6 = 5 32 0 ci cl os K ER N E L Estrutura do programa VSYNC VBLANK KERNEL (desenha a tela) OVERSCAN Estrutura do programa VSYNC VBLANK OVERSCAN Playfield Loop Principal (eterno) Kernel loop X: 0 a 191 (192 scanlines) Estrutura do programa VSYNC VBLANK OVERSCAN 11 chars x 8 linhas x 2 linhas por scanline = 176 scanlines Começando o programa PROCESSOR 6502 INCLUDE "vcs.h" ORG $F000 ; Início do cartucho VSYNC VBLANK KERNEL OVERSCAN Início do frame (loop principal) InicioFrame: lda #%00000010 ; VSYNC inicia sta VSYNC ; setando o bit 1 REPEAT 3 ; e dura 3 scanlines sta WSYNC ; (WSYNC = aguarda fim REPEND ; da scanline) lda #0 ; VSYNC finaliza sta VSYNC ; limpando o bit 1 VSYNC VBLANK KERNEL OVERSCAN Desligando elementos lda #$00 sta ENABL ; Desliga ball sta ENAM0 ; Desliga missiles sta ENAM1 sta GRP0 ; Desliga players sta GRP1 VSYNC VBLANK KERNEL OVERSCAN Configurando o Playfield sta COLUBK ; Cor de fundo (0=preto) sta PF0 ; PF0 e PF2 ficam apagados sta PF2 lda #$FF ; Cor do playfield sta COLUPF ; (possivelmente amarelo) lda #$00 ; Reset no bit 0 do CTRLPF sta CTRLPF ; para duplicar o PF ldx #0 ; X=contador de scanlines VSYNC VBLANK KERNEL OVERSCAN VBLANK propriamente dito REPEAT 37 ; VBLANK dura 37 scanlines, sta WSYNC ; (poderíamos ter lógica REPEND ; do jogo aqui) lda #0 ; Finaliza o VBLANK, sta VBLANK ; "ligando o canhão" VSYNC VBLANK KERNEL OVERSCAN Kernel Scanline: cpx #174 ; Se acabou a frase, pula bcs FimScanline; o desenho txa ; Y=X/2 (usando o shift lsr ; lógico para dividir, tay ; que só opera no A) lda Frase,y ; Frase,Y = mem(Frase+Y) sta PF1 ; PF1 = bits 5 a 11 do ; playfield VSYNC VBLANK KERNEL OVERSCAN Kernel (continuação) FimScanline: sta WSYNC ; Aguarda fim da scanline inx ; Incrementa contador e cpx #191 ; repete até até a bne Scanline ; completar a tela VSYNC VBLANK KERNEL OVERSCAN Fechando o loop principal Overscan: lda #%01000010 ; "Desliga o canhão": sta VBLANK ; 30 scanlines de REPEAT 30 ; overscan... sta WSYNC REPEND jmp InicioFrame ; ...e começa tudo de ; novo! VSYNC VBLANK KERNEL OVERSCAN A frase, bit a bit Frase: .BYTE %00000000 ; H .BYTE %01000010 .BYTE %01111110 .BYTE %01000010 .BYTE %01000010 .BYTE %01000010 .BYTE %00000000 .BYTE %00000000 ; E .BYTE %01111110 ... A frase, bit a bit ... .BYTE %00000000 ; D .BYTE %01111000 .BYTE %01000100 .BYTE %01000010 .BYTE %01000010 .BYTE %01000100 .BYTE %01111000 .BYTE %00000000 ; Valor final do PF1 Configurações finais ORG $FFFA ; Ficam no final da ; ROM (cartucho) .WORD InicioFrame ; Endereço NMI .WORD InicioFrame ; Endereço BOOT .WORD InicioFrame ; Endereço BRK END Montando e Executando dasm fonte.asm -oromcartucho.bin -f3 http://stella.sourceforge.net/ Técnicas Avançadas Placar com playfield Placar com playfield Para identificar os placares, é possível usar as cores dos players no playfield, setando o bit 1 do registrador CTRLPF (score mode) O lado esquerdo fica com a cor do P0, e o direito com a cor do P1 CORES DOS PLAYERS (isso dá idéias para melhorar nosso Hello World?) (isso dá idéias para melhorar nosso Hello World?) Placar com playfield Problema: como mostrar coisas DIFERENTES em cada lado? Solução: mudar o playfield enquanto o canhão passa! canhão configure o playfield para “3” no início da scanline quando o canhão estiver no meio, configure o playfield do “1”... canhão canhão ...e você terá um desenho diferente do outro lado! Mundos gigantes Pitfall! Cada uma das 256 telas é definida (objetos, árvores, paredes...) por 1 byte, que deveriam ser armazenados no cartucho (ROM) Tamanho da tabela: 256 bytes Pitfall! Solução: gerador de sequência com aleatoriedade aceitável e que também gera o valor anterior a partir do atual, para voltar telas (LFSR bidirecional) Tamanho do código: 50 bytes http://en.wikipedia.org/wiki/Linear_feedback_shift_register http://en.wikipedia.org/wiki/Linear_feedback_shift_register River Raid A mesma solução é aplicada com um gerador de 16 bits (que eventualmente se repete), com pequenos ajustes para tornar os primeiros setores mais fáceis. Ao passar a ponte, o jogo guarda o valor atual, recuperando em caso de morte para voltar no mesmo setor Posição horizontal Posição horizontal Não existe um registrador para determine a posição horizontal de players, missiles ou ball Você tem que contar o tempo até que o canhão esteja na posição e acionar o strobe correspondente PONTOS DE STROBE (na teoria) Dá pra calcular... 1 ciclo de CPU = 3 pixels WSYNC = 20 ciclos posição x ≈ (ciclos – 20) * 3 ...mas é aproximado, porque o TIA só lê os registros a cada 5 ciclos de CPU, tornando inviável para movimento ↔ Soluções Você pode mover player, missile ou ball relativamente à posição anterior, usando um registrador de 4 bits (isto é, movendo de -7 a +8 pixels) E o missile pode ser posicionado no meio do player correspondente, tornando fácil “atirar” ele (daí o nome) PONTOS DE STROBE MOVIMENTO ↕ basta desenhar o player/missle em uma scanline diferente a cada frame MOVIMENTO ↔ registradores HMP0/1 e HMM0/1 Placar com múltiplos dígitos Placar com múltiplos dígitos O truque é o mesmo do placar com playfield: mudar a imagem com o canhão andando, mas o timing tem que ser muito mais preciso Digamos que o placar seja 456789... Placar com múltiplos dígitos Comece cada scanline com a linha do 4 no GRP0 e do 5 no GRP1. Configure NUSIZ0 e NUSIZ1 para repetir três vezes: 4 4 4 5 5 5 Player 0 Player 1 Placar com múltiplos dígitos Posicione o player 1 à direita do player 0, encavalando as cópias: 454545 Player 0 Player 1 Placar com múltiplos dígitos Troque o desenho dos players (GRP0/GRP1) sincronizando com o canhão, assim: CANHÃO 454545 Placar com múltiplos dígitos Quando o canhão estiver terminando a 1ª cópia do player 1, altere o player 0 para 6 e o player 1 para 7: CANHÃO 454545 Placar com múltiplos dígitos Repita o truque ao final da 2ª cópia do player 2, dessa vez alternado o player 0 para 8 e o player 1 para 9 CANHÃO 456767 Placar com múltiplos dígitos Faça a mesma coisa para cada scanline do placar! CANHÃO 456789 Placar com múltiplos dígitos É mais difícil do que parece: não dá tempo de carregar bitmaps da memória quando o canhão passa, e só temos 3 registradores para guardar4 dígitos... ...mas é isso que torna divertido! Conclusões Tirando leite de pedra Quando observar um jogo de Atari, tente identificar os truques que o(a) programador(a) usou: como dividiu a tela, o que tem em cada scanline, como gastou a RAM e a ROM... Mãos à obra! Você pode fazer seu jogo de Atari – é um desafio de programação divertido! Será preciso estudar várias coisas que não detalhamos: contagem de ciclos, som, leitura de joysticks... mas dá! Para aprender mais O nosso Hello, World: http://pastebin.com/abBRfUjd Sorteio 2600 http://github.com/chesterbr/sorteio2600 Racing The Beam (livro): http://bit.ly/dSqhjS Palestra David Crane (Pitfall): http://youtu.be/MBT1OK6VAIU Tutoriais do Crane para iOS: http://bit.ly/9pwYHs e http://bit.ly/qWBciZ Stella Programmer's Guide: http://emu-docs.org/?page=Atari%202600 Código-fonte de jogos clássicos: http://classicdev.org/wiki/2600/Source_Code Especificações do Atari: http://nocash.emubase.de/2k6specs.htm Referência 6502: http://bit.ly/hxG5c6 Emulador no browser: http://jogosdeatari.com.br/ Tutorial Andrew Dave: http://bit.ly/ptQDdA (o site todo é bom) Cartucho com leitor de SD: http://harmony.atariage.com/ BAtari (compilador BASIC): http://bataribasic.com Exemplos de som no TIA: http://bit.ly/tnbPrp Bankswitching (mais ROM/RAM): http://bit.ly/tqhLZk http://pastebin.com/abBRfUjd http://github.com/chesterbr/sorteio2600 http://bit.ly/dSqhjS http://youtu.be/MBT1OK6VAIU http://bit.ly/9pwYHs http://bit.ly/qWBciZ http://emu-docs.org/?page=Atari%202600 http://classicdev.org/wiki/2600/Source_Code http://nocash.emubase.de/2k6specs.htm http://bit.ly/hxG5c6 http://jogosdeatari.com.br/ http://bit.ly/ptQDdA http://harmony.atariage.com/ http://bataribasic.com/ http://bit.ly/tnbPrp http://bit.ly/tqhLZk Dúvidas? Obrigado! @chesterbr http://slideshare.net/chesterbr http://chester.me http://slideshare.net/chesterbr Créditos e Licenciamento Esta apresentação está licenciada sob os termos da licença Creative Commons “by-nc” 3.0, observadas as exceções abaixo O slide de abertura é baseado em ilustração © 2011 Ila Fox, licenciada exclusivamente para o autor e não inclusa na licença acima Fotos e ilustrações de terceiros usados sob premissa de “fair use” têm sua autoria mencionada e também excluídos da licença acima Atari™, Adventure™, Donkey Kong™, Pitfall™, Super Mario™ e outros personagens/jogos citados para fins ilustrativos, bem como suas imagens e logomarcas, são de propriedade de seus detentores, com todos os direitos reservados, não havendo qualquer relação deles com o autor http://creativecommons.org/licenses/by-nc/3.0/ http://www.ilafox.com/ http://creativecommons.org/licenses/by-nc/3.0/ Slide 1 Slide 2 Slide 3 Slide 4 Slide 5 Slide 6 Slide 7 Slide 8 Slide 9 Slide 10 Slide 11 Slide 12 Slide 13 Slide 14 Slide 15 Slide 16 Slide 17 Slide 18 Slide 19 Slide 20 Slide 21 Slide 22 Slide 23 Slide 24 Slide 25 Slide 26 Slide 27 Slide 28 Slide 29 Slide 30 Slide 31 Slide 32 Slide 33 Slide 34 Slide 35 Slide 36 Slide 37 Slide 38 Slide 39 Slide 40 Slide 41 Slide 42 Slide 43 Slide 44 Slide 45 Slide 46 Slide 47 Slide 48 Slide 49 Slide 50 Slide 51 Slide 52 Slide 53 Slide 54 Slide 55 Slide 56 Slide 57 Slide 58 Slide 59 Slide 60 Slide 61 Slide 62 Slide 63 Slide 64 Slide 65 Slide 66 Slide 67 Slide 68 Slide 69 Slide 70 Slide 71 Slide 72 Slide 73 Slide 74 Slide 75 Slide 76 Slide 77 Slide 78 Slide 79 Slide 80 Slide 81 Slide 82 Slide 83 Slide 84 Slide 85 Slide 86 Slide 87 Slide 88 Slide 89 Slide 90 Slide 91 Slide 92 Slide 93 Slide 94 Slide 95 Slide 96 Slide 97 Slide 98 Slide 99 Slide 100 Slide 101 Slide 102 Slide 103 Slide 104 Slide 105 Slide 106 Slide 107 Slide 108 Slide 109 Slide 110 Slide 111 Slide 112 Slide 113 Slide 114 Slide 115 Slide 116 Slide 117 Slide 118 Slide 119 Slide 120 Slide 121 Slide 122 Slide 123 Slide 124 Slide 125 Slide 126 Slide 127 Slide 128 Slide 129 Slide 130 Slide 131 Slide 132 Slide 133 Slide 134 Slide 135 Slide 136 Slide 137 Slide 138 Slide 139 Slide 140 Slide 141
Compartilhar