Programação para Atari 2600

Preview:

DESCRIPTION

Palestra apresentada em 27/Ago/2011 no Dev in Sampa (http://devinsampa.com.br/), em 06/Nov/2011 no Dev In Vale e em 11/Fev/2012 no Campus Party Brasil (5a. edição, #cpbr5) O vídeo da palestra no Dev In Sampa (filmada pelo @agaelebe) está disponível em: http://chester.blog.br/archives/2011/08/palestra-sobre-programacao-para-atari-2600-no-dev-in-sampa-2011.html

Citation preview

game program™PROGRAMAÇÃO PARA

ATARI 2600Use with Joystick Controllers

Proposta

Entender o que torna o Ataritã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

Palestrante

@chesterbrhttp://chester.me

Palestrante

@chesterbrhttp://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ípicotransforma padrões de bitsarmazenados em memória(VRAM) em pixels e cores

VRAMVRAM

VRAM

3844447C4444EE00

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 emposiçõ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 ←← leituraPF1 = 00000000 leitura →→PF2 = 00000000 ←← leituraREFLECT = 0

scanline resultante████████████████████████████████████████

Configurando o playfield

PF0 = 0001 ←← leituraPF1 = 00000000 leitura →→PF2 = 00000000 ←← leituraREFLECT = 0

scanline resultante████████████████████████████████████████

Configurando o playfield

PF0 = 0011 ←← leituraPF1 = 00000000 leitura →→PF2 = 00000000 ←← leituraREFLECT = 0

scanline resultante████████████████████████████████████████

Configurando o playfield

PF0 = 0111 ←← leituraPF1 = 00000000 leitura →→PF2 = 00000000 ←← leituraREFLECT = 0

scanline resultante████████████████████████████████████████

Configurando o playfield

PF0 = 1111 ←← leituraPF1 = 11110000 leitura →→PF2 = 00000000 ←← leituraREFLECT = 0

scanline resultante████████████████████████████████████████

Configurando o playfield

PF0 = 1111 ←← leituraPF1 = 11111110 leitura →→PF2 = 00010101 ←← leituraREFLECT = 0

scanline resultante████████████████████████████████████████

Configurando o playfield

PF0 = 1111 ←← leituraPF1 = 11111110 leitura →→PF2 = 00010101 ←← leituraREFLECT = 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)000001010011100101110111

NU

SIZ

n

Ligando o REFPn000001010011100101110111

NU

SIZ

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 telaNTSC: 262 scanlines por frame

19.912 / 262 = 76 ciclos por scanline

Contas de padaria:

CPU: 19.912 ciclos por telaNTSC: 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 6502AD 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 6502AD 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 6502AD LDA $0200000269 ADC #01018D STA $02010102

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 $0200ADC #01STA $0201...

foo.bin

AD000269018D0102...

ASSEMBLER

DASM

● Macro Assembler 6502● Inclui headers para Atari● Multiplataforma● Livre (GPLv2)

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

Instruções do 6502 = mais relevantes para o Atari

Transferindo Dados

LDA, LDX, LDY = LoadSTA, STX, STY = StoreTAX, TAY, TXA,TYA, TSX, TXS = Transfer

LDA #$10 0x10→A STY $0200 Y→m(0x0200)TXA X→A

AritméticaADC, 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ógicoROL, 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ãoBEQ, BNE = desvia se Equal/NãoBVS, BVC = desvia se Overflow/NãoBMI, BPL = desvia se Minus/Plus

CPY $1234 se y=m(0x1234),BEQ $0200 0x0200→PC

Pilha e Subrotinas

JSR, RTS = chama subrotina/retornaPHA, PLA = push/pop(pull) do APHP, PLP = push/pop do status (P)

JMP $1234 0x1234→PCJSR $1234 PC(+3)→pilha,

0x1234→PCRTS pilha→PC

O Resto...

NOP = No Operation (nada!)JMP = Desvio direto (GOTO)SEC, CLC = Set/Clear CarrySEV, CLV = Set/Clear oVerflowSEI, CLI = Set/Clear Interrupt-offSED, CLD = Set/Clear DecimalRTI = Return from InterruptBRK = 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 escreverna 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

ICA

DO

JOG

O(3

+37

+30

).76

= 5

320

cicl

osK

ERN

E L

Estrutura do programaVSYNC

VBLANK

KERNEL(desenha a tela)

OVERSCAN

Estrutura do programaVSYNC

VBLANK

OVERSCAN

Playfield

LoopPrincipal

(eterno)Kernel

loop X: 0 a 191(192 scanlines)

Estrutura do programaVSYNC

VBLANK

OVERSCAN

11 chars x8 linhas x

2 linhas por scanline =

176 scanlines

Começando o programa

PROCESSOR 6502INCLUDE "vcs.h"

ORG $F000 ; Início do cartucho

VSYNC

VBLANK

KERNEL

OVERSCAN

Início do frame (loop principal)

InicioFrame:lda #%00000010 ; VSYNC iniciasta VSYNC ; setando o bit 1REPEAT 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 shiftlsr ; 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

; playfieldVSYNC

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 deREPEAT 30 ; overscan...

sta WSYNCREPENDjmp 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 Executandodasm 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 diferentedo 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

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 paradetermine a posição horizontal de

players, missiles ou ball

Você tem que contar o tempoaté que o canhão esteja na posiçãoe acionar o strobe correspondente

PONTOS DE STROBE(na teoria)

Dá pra calcular...

1 ciclo de CPU = 3 pixelsWSYNC = 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çõesVocê 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 emuma 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ígitosComece 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 paracada 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 guardar 4 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 maisO nosso Hello, World: http://pastebin.com/abBRfUjdSorteio 2600 http://github.com/chesterbr/sorteio2600Racing 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%202600Có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.comExemplos de som no TIA: http://bit.ly/tnbPrp Bankswitching (mais ROM/RAM): http://bit.ly/tqhLZk

Dúvidas?Obrigado!

@chesterbr

http://slideshare.net/chesterbrhttp://chester.me

Créditos e LicenciamentoEsta 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

Recommended