atari 2600 vcs programming

Post on 19-Jun-2015

3.459 Views

Category:

Technology

31 Downloads

Preview:

Click to see full reader

DESCRIPTION

Introduces the core architecture of the Atari 2600 graphics chip (TIA), its 6502 CPU and showcases a "Hello, World!" application that can be executed on an emulator or on the real console. Includes reference links for those who want to learn more. Originally presented in Brazil at events such as Dev in Sampa and Campus Party.

TRANSCRIPT

game program™ATARI 2600

PROGRAMMINGUse with Keyboard Controllers

PROGRAM CONTENTS 2011-2013 CHESTER, INC.

©

What

An overview of the Atari 2600 architecture, covering everything

needed to create a “Hello, World!” program that can run on emulators

or even on a real Atari

http://slideshare.net/chesterbr

Why● Pure nostalgia● Homebrew games● Demoscene● Appreciate masterworks such as Enduro, Pitfall! or River Raid● Feel better about today's tools

and hardware limitations :-)

http://slideshare.net/chesterbr

@chesterbrhttp://chester.me

Who

Atari 2600(Video Computer System)

Over 600 titles...imagem: mitchelaneous.com

but why were they so... “Atari-ish”?

Let's look inside and find out!(Atari 2600 Jr. printed circuit board)

CPU: 6507

CPU: 65076502

(same thing software-wise, and way more info available)

Video: TIA

Everything else: RIOT (6532)

Look ma, no O.S.!

Atari programs talk directly to the hardware – there is no middle man!

Its 6502 CPU only “understands” memory reads and writes, so all the other chips are hard-wired to act as

memory (even those who aren't)

Memory Map(very, very, very simplified*)

0000-002C – TIA (write)0030-003D – TIA (read)0080-00FF – RIOT (RAM)0280-0297 – RIOT (I/O, Timer)F000-FFFF – Cartridge (ROM)

*http://nocash.emubase.de/2k6specs.htm

Memory Map

F000-FFFF – Cartridge (ROM)

(this is not your biggest problem...)

4 KBytes!

Memory Map

0080-00FF – RIOT (RAM)

(and still not your biggest problem)

128 BYTES!!!!!(1/8 of a KB)

VRAM(frame buffer)

Typical video chips translatebit patterns stored on Video RAM

(VRAM) into pixels and colors

VRAMVRAM

VRAM

3844447C4444EE00

VRAM

Screen resolution and color depthare subject to VRAM size limits

Memory was expensive on the 70s/80s, leading to trade-offs

How much VRAM does an Atari have?

Memory Map

0000-002C – TIA (write)0030-003D – TIA (read)0080-00FF – RIOT (RAM)0280-0297 – RIOT (I/O, Timer)F000-FFFF – Cartridge (ROM)

Memory Map

????-???? – VRAM

Memory Map

0 bytes !!!!

????-???? – VRAM

right, now yougot a problem...

Racing the Beam

Since we can't just write pixels to some VRAM frame buffer, our code will need to work a bit closer to

the TV hardware, with a little help from a very unique chip...

TIA(Television Interface Adaptor)

How a TV set works

Image: cc-by wikipedia user Grm_wnr

Scanlines

public domain illustration by Ian Harvey

60 framesper second

(NTSCstandard)

TIA is scanline-oriented

As the beam draws each scanline, the game program must set TIA registers to configure the objects drawn on it

Most of this objects have only one color, making multiple colors on the

same scanline theoretically impossible...

...which explains:

vs.

constraints ⇒ creativity

vs.

Screen Objects

● Playfield (PF)● Players (P0, P1)● Missiles/Ball (M0, M1, BL)

Scanlines will be rendered based on how we configure TIA's screen objects:

Playfield (PF)

20-bit pattern with a foreground and a background color, rendered

over the left side of the scanline

The right side will either repeat or refect the same pattern (the later generating a symmetrical image)

PLAYFIELD

PLAYFIELD

PLAYFIELD

PLAYFIELD

Playfield configuration

PF0 = 0000 ←← orderPF1 = 00000000 order →→PF2 = 00000000 ←← orderREFLECT = 0

resulting scanline

Playfield configuration

PF0 = 0001 ←← orderPF1 = 00000000 order →→PF2 = 00000000 ←← orderREFLECT = 0

resulting scanline_ _

Playfield configuration

PF0 = 0011 ←← orderPF1 = 00000000 order →→PF2 = 00000000 ←← orderREFLECT = 0

resulting scanline__ __

Playfield configuration

PF0 = 0111 ←← orderPF1 = 00000000 order →→PF2 = 00000000 ←← orderREFLECT = 0

resulting scanline___ ___

Playfield configuration

PF0 = 1111 ←← orderPF1 = 11110000 order →→PF2 = 00000000 ←← orderREFLECT = 0

resulting scanline________ _______

Playfield configuration

PF0 = 1111 ←← orderPF1 = 11111110 order →→PF2 = 00010101 ←← orderREFLECT = 0

resulting scanline___________ _ _ _ ___________ _ _ _

Playfield configuration

PF0 = 1111 ←← orderPF1 = 11111110 order →→PF2 = 00010101 ←← orderREFLECT = 1

resulting scanline___________ _ _ _ _ _ _ ___________

___________ _ _ _ _ _ _ ___________

Players (P0, P1)Each one is an independent 8 bit pattern (GRP0/GRP1) with a foreground color

(COLUP0 / COLUP1) that can be positioned at any column of the scanline

e.g.: 10100001 → ████████

PLAYERS

PLAYERS

Players

Each player can be horizontally stretched, multiplied or inverted by

setting NUSIZn / REFPn (n=0/1)

(number/size and reflect player)

NUSIZ0 (or NUSIZ1)000001010011100101110111

NU

SIZ

n

With REFP0 (or REFP1) on000001010011100101110111

NU

SIZ

n

NUSIZn

NUSIZn

NUSIZn

NUSIZn

NUSIZn

Missiles/Ball (M0/M1/BL)

Can be positioned just like players, but no bit pattern, just a pixel (although it can be horizontally stretched 2/4/8x)

M0/M1 use P0/P1colors, whileBL uses the PF foreground color

MISSILES

BALL

BALL

BALL

MISSILE

BALL

MISSILE

Master Plan

For each scanline, configure the options for each object before the beam reaches its intended position

The time slot is very short, forcing programmers to pick and choose what to change, reusing as much as they can

How short?

6502 ≈ 1,19Mhz (1.194.720 cycles/sec)NTSC: 60 frames per second

1.194.720/60 ≅ 19.912 cycles per frame

How short?

CPU: 19.912 cyles per frameNTSC: 262 scanlines per frame

19.912 / 262 = 76 cycles per scanline

How short?

CPU: 19.912 cyles per frameNTSC: 262 scanlines per frame

19.912 / 262 = 76 cycles per scanline

and what can we do with 76 cycles?(by the way: WTF is a “cycle”?)

Assembly 6502

6502

6502 (Atari-wise)

Reads a program from the cartridge (ROM) composed of operations that

manipulate and transfer bytes between cartridge, RIOT (RAM, I/O, timers) and TIA, keeping state on internal registers

Operations

Each operation that composes a 6502 program in memory is identified by a1-byte opcode and can be followed

by up to 2 bytes of parameters

An instruction can take up to 6cycles to be executed

Registers

A = Accumulator (8 bits)X, Y= Indexes (8 bits)

S = Stack Pointer (8 bits)P = Status (fags, 8 bits)PC = Program Counter (16 bits)

Example program

“add 2 to a value stored at a memory position; store the result into another memory position”

Implementation

● Read the byte stored on memoryposition 0200 into register A

● Add 2 to register A's value

● Write register A's value into memory position 0201

6502 Machine CodeAD Opcode (Memory → A)00 Last part of “0200”02 First part of “0200”69 Opcode (value + A → A)02 Value to add8D Opcode (A → Memory)01 Last part of “0201”02 First part of “0201”

6502 Assembly Language

Associates the 151 opcodes with 56 mnnemonic instructions

and a notation for their parameters (access mode)

6502 Machine CodeAD Opcode (Memory → A)00 Last part of “0200”02 First part of “0200”69 Opcode (value + A → A)02 Value to add8D Opcode (A → Memory)01 Last part of “0201”02 First part of “0201”

Assembly 6502AD LDA $0200000269 ADC #02028D STA $02010102

AssemblerProgram that reads a text file

written in Assembly language and assembles a binary file with the corresponding machine code

foo.asm

LDA $0200ADC #02STA $0201...

foo.bin

AD000269028D0102...

ASSEMBLER

Macro Assembler

ORG $0100 ; Start @ memory 0100 ... SomeLabel:

LDX #$10 ; No idea where thisDEX ; will be in memory,BNE SomeLabel ; and don't need to!...

DASM

● 6502 Macro Assembler● Includes Atari headers● Multiplataform● Free and open-source (GPLv2)

http://dasm-dillon.sourceforge.net/

Notation (for today)

#... = decimal value #$... = hex value $... = hex address $... , X = hex address + X

http://www.obelisk.demon.co.uk/6502/addressing.html

6502 Instruction Set = most relevant for Atari 2600 programming

Data Transfer

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

ArithmeticADC, SBC = +,- (w/ carry)INC, INX, INY = ++DEC, DEX, DEY = --

ADC $0100 m(0x100)+A→A INC $0200 m(0x200)+1→

m(0x200)DEX X-1→X

Bit Operations

AND, ORA, EOR = &, |, ^ (A) ASL, LSR = Arithmetic shiftROL, ROR = “Rotating” shift

AND #$11 A&0x11→ALSR A>>1→A (A/2→A)ROR A>>1 (bit 7=carry)

Comparing / Branching

CMP, CPX, CPY = compare A/X/Y (-)BCS, BCC = ⇗ if carry set / clearBEQ, BNE = ⇗ if equal / not equalBVS, BVC = ⇗ if overfow set / clearBMI, BPL = ⇗ if minus / plus

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

Stack and Subroutines

JSR, RTS = call/return subroutinePHA, PLA = push / pull APHP, PLP = push / pull status (P)

JSR $1234 PC(+3)→stack,0x1234→PC

RTS stack→PC

Everything else...

NOP = No OperationJMP = Direct Jump (GOTO)SEC, CLC = Set/Clear CarrySEV, CLV = Set/Clear oVerfowSEI, 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!

Horizontal writing is hard(too many pixels per scanline)

Hello, World!

Vertical writingis the way →

(less pixels/scanline)

We can use a playeror the playfield

Hello, World!

Our display kernel will configure each pair of visible scanlines with a byte

from a “hello world” bitmap (stored on the cart, just after the code)

Let's find which are visible, and how we need to deal with TV timings

Source: Stella Programmers Guide, Steve Wright, 1979

GA

ME

LOG

IC(3

+37

+30

).76

= 5

320

cycl

esK

ERN

E L

Program structureVertical Sync

Vertical Blank

Overscan

Playfield

main loop

(infinite)Kernel

X: count 0 to 191(192 scanlines)

Program structureVertical Sync

Vertical Blank

Overscan

11 chars *8 bytes *

2 scanlines per byte =

176 scanlines

Program structure

Vertical Sync

Vertical Blank

Kernel

Overscan

Let's begin!

PROCESSOR 6502INCLUDE "vcs.h"

ORG $F000 ; Cart begins here

Vertical Sync

Vertical Blank

Kernel

Overscan

Frame (main loop) start

StartFrame:lda #%00000010 ; Signal VSYNC start bysta VSYNC ; setting bit 1REPEAT 3 ; lasts 3 scanlines

sta WSYNC ; (WSYNC = wait until REPEND ; scanline is finished)lda #0 ; Signal VSYNC end (and sta VSYNC ; VBLANK start)

Vertical Sync

Vertical Blank

Kernel

Overscan

Vertical Blank

PreparePlayfield:lda #$00

sta ENABL ; Disable ball sta ENAM0 ; Disable missiles sta ENAM1 sta GRP0 ; Disable players sta GRP1 ; (with a 0s-only shape)

Vertical Sync

Vertical Blank

Kernel

Overscan

Vertical Blank

sta COLUBK ; Background (0=preto) sta PF0 ; PF0 and PF2 stay off sta PF2 lda #$FF ; Playfield color sta COLUPF ; (yellow-ish) lda #$00 ; Clear CTRLPF bit 0 to sta CTRLPF ; repeat playfield ldx #0 ; X: scanline counter

Vertical Sync

Vertical Blank

Kernel

Overscan

Finish Vertical Blank

REPEAT 37 ; VBLANK lasts 37 scanlinessta WSYNC ; (useful for game logic)

REPEND ; lda #0 ; Signals VBLANK end (willsta VBLANK ; “turn on the beam”)

Vertical Sync

Vertical Blank

Kernel

Overscan

Scanline (inner loop)

Scanline:cpx #174 ; Phrase over? bcs ScanlineEnd; if so, skip

txa ; Y=X÷2 (logic shift →lsr ; divides A by 2)tay ; lda Phrase,y ; label,Y = mem[label+Y] sta PF1 ; PF1 = playfield (bits

; 4 to 11)Vertical Sync

Vertical Blank

Kernel

Overscan

Scanline (close inner loop)

ScanlineEnd:sta WSYNC ; Finish current scanline inx ; X=line counter cpx #191 ; last visible scanline? bne Scanline ; unless so, repeat!

Vertical Sync

Vertical Blank

Kernel

Overscan

Overscan (close main loop)

Overscan:lda #%00000010 ; “turn off” beam againsta VBLANK ; 30 scanlines ofREPEAT 30 ; overscan...

sta WSYNCREPENDjmp StartFrame ; ...and start it over,

; forever and ever!Vertical Sync

Vertical Blank

Kernel

Overscan

Hello...

Phrase:.BYTE %00000000 ; H.BYTE %01000010.BYTE %01111110.BYTE %01000010.BYTE %01000010.BYTE %01000010.BYTE %00000000.BYTE %00000000 ; E.BYTE %01111110

...

...world

....BYTE %00000000 ; D.BYTE %01111000.BYTE %01000100.BYTE %01000010.BYTE %01000010.BYTE %01000100.BYTE %01111000.BYTE %00000000 ; PF1 last value (!)

6502 configuration

ORG $FFFA ; Located at the end; of ROM (cart)

.WORD FrameStart ; NMI address

.WORD FrameStart ; BOOT address

.WORD FrameStart ; BRK address

END

Assemble!dasm source.asm -ocart.bin -f3

http://stella.sourceforge.net/

Advanced Tricks

Playfield-based score

Playfield-based score

The PF color can be replaced with player colors (P0 = left side; P1 = right side) by turning CTRLPF's

score mode bit on

PLAYERS' COLORS

(how could this improve our Hello World?)

(how could this improve our Hello World?)

Playfield-based score

Q: How can different patterns be shown at each side of the playfield?

A: Change the pattern when the beam is halfway through the scanline

(“race the beam”)

beam

...and you have a different shapeat the other half!

Large worlds

Pitfall!

http://pitfallharry.tripod.com/MapRoom/PitfallMap.html

Pitfall!

Screen configuration (logs, vines, trees, stairs, crocs) was squeezedinto a single byte, but 255 screens(bytes) are still a huge ROM table

(for Atari standards)

http://pitfallharry.tripod.com/MapRoom/PitfallMap.html

Pitfall!

David Crane implemented a sequence generator (LFSR), which, for a given value, would give the previous/next ones, replacing the 255-byte table

with a 50-byte piece of code

http://en.wikipedia.org/wiki/Linear_feedback_shift_register

River Raid

River Raid

Carol Shaw had used a 16-bit generator, resulting in thousands of non-repeating river sectors (tweaking the interpreter

to make the first few ones easier)

When a player loses a life, rendering restarts from the last generated number,

that is, back on the last bridge

Horizontal positioning

Horizontal positioning

The horizontal position of a player / missile / ball is not a writable register

Games must sync to with the beam and write to the appropriate strobe register

when it is on the desired location

STROBE TARGETS(in theory)

You can calculate...

1 CPU cycle = 3 “color clocks” (pixels)Horizontal Blank = 22.6 cycles

horiz. position ≈ (cycles – 22.6) * 3

...but it is an estimate, because TIA only reads its registers every 5 CPU cycles

Smooth ↔ movement is also hard

AlternativesA 4-bit register allows moving a player, missile or ball relative to its previous

position (adding -7 to +8 pixels)

The missile can also be reset to the middle of its player, making it easy to

“fire” it over and over

STROBE TARGETS

VERTICAL MOVEMENTJust start on a different scanline at each frame

HORIZONTAL MOVEMENTstrobe registers HMP0/1 e HMM0/1

Multi-digit score

Multi-digit score

The trick is the same of the playfield-based score (change the registers while the beam is drawing the scanline), but timing is much more of an issue here

Let's say the score is 456789...

Multi-digit scoreBegin the scanline with the bits for 4 on GRP0 and those for 5 on GRP1

Configure NUSIZ0 and NUSIZ1 fora triple repetition:

4 4 4 5 5 5

Player 0 Player 1

Multi-digit score

Set player 1 position just to the right of player 0, overlapping the triplets

454545

Player 0

Player 1

Multi-digit score

Change the patterns (GRP0/GRP1) syncing with the beam, like this:

BEAM

454545

Multi-digit score

When the beam is about to finish player 1's 1st copy, change player 0 to

6 and player 1 to 7:

BEAM

454545

Multi-digit score

Repeat the trick after the 2nd player 2 copy, this time changing player 0 to 8

and player 1 to 9

BEAM

456767

Multi-digit score

Repeat it for each scanline.Easy! #not

BEAM

456789

Multi-digit score

There are other hurdles: we can't load replaced digits from memory, and we

only have 3 memory-writable registers to store 6 bit patterns...

...and that is why it is fun!

Final Words

A new look to the old school

Knowing what the Atari 2600 was designed to do, we can appreciate

games that push it beyond its limitsby identifying “impossible” things

It is just the beginning!

The Atari homebrew scene is alive and kicking, and these are the basics you

need to create your own games/demos

There are several uncovered topics (sound, timers, collision, I/O...), but with

time and dedication, you can do it!

To learn moreHello, World: https://gist.github.com/chesterbr/5864935 Sorteio 2600 http://github.com/chesterbr/sorteio2600Racing The Beam (book): http://bit.ly/dSqhjS David Crane's talk: http://youtu.be/MBT1OK6VAIU David Crane's iOS tutorials: http://bit.ly/9pwYHs and http://bit.ly/qWBciZ Stella Programmer's Guide: http://emu-docs.org/?page=Atari%202600Classic games disassembled: http://classicdev.org/wiki/2600/Source_Code Atari 2600 specs: http://nocash.emubase.de/2k6specs.htm 6502 reference: http://bit.ly/hxG5c6 In-browser emulator: http://jogosdeatari.com.br/ Andrew Dave's tutorial: http://bit.ly/ptQDdA (the whole site is great)Harmony (SD-reader cart): http://harmony.atariage.com/BAtari (BASIC compiler): http://bataribasic.comTIA sound examples: http://bit.ly/tnbPrp Bankswitching (more ROM/RAM): http://bit.ly/tqhLZk

Questions?Thank you!

@chesterbr

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

Credits and LicenseThis presentation is available under the licença Creative Commons “by-nc” 3.0 l,

noticing the exceptions below

Images from third parties were included (with due credits) underfair use assumption and/or under their respective licenses.

These are excluded from the license above.

Atari™, Adventure™, Donkey Kong™, Pitfall™, Super Mario™ and likewise characters/games/systems are mentioned uniquely for

illustrative purposes, also under fair use assumption. They are property of their rights holders, and are also excluded from the license above.

top related