First things first - head over to MiniDig - best of stella and download the Stella Programmer's Guide from the docs page. I've also attached it to this blog entry, but you should still check out what's available over at MiniDig.
Also, for this tutorial you'll need to have DASM to compile the code as well as Stella and/or a real 2600 with a Harmony cart to run your code.
The heart of the Atari is TIA, the Television Interface Adaptor. It's the video chip, sound generator, and also handles some of the controller input. As a video chip, TIA is very unusual. Most video game systems have memory that holds the current state of the display. Their video chip reads that memory and uses that information to generate the display. But not TIA - memory was very expensive at the time, so TIA was designed with a handful of registers that contain just the information needed to draw a single scanline. It's up to our program to change those registers in realtime so that each scanline shows what its supposed to. It's also up to our program to generate a "sync signal" that tells the TV when its time to start generating a new image.
Turn to page 2 of the programmer's guide. You'll find the following diagram, which I've slightly modified:
The Horizontal Blank is part of each scanline, so we don't need to worry about generating it. Everything else though is up to us! We need to generate a sync signal over 3 scanlines, after which we need to wait 37 scanlines before we tell TIA to "turn on" the image output. After that we need to update TIA so each of the 192 scanlines that comprise visible portion of the display show what they're supposed to. Once that's done, we "turn off" the image output and wait 30 scanlines before we start all over again.
In the source code, available below, you can see the Main loop which follows the diagram:
Main: jsr VerticalSync ; Jump to SubRoutine VerticalSync jsr VerticalBlank ; Jump to SubRoutine VerticalBlank jsr Kernel ; Jump to SubRoutine Kernel jsr OverScan ; Jump to SubRoutine OverScan jmp Main ; JuMP to Main
Each of the subroutines handles what's needed, such as this section which generates the sync signal:
VerticalSync: lda #2 ; LoaD Accumulator with 2 so D1=1 sta WSYNC ; Wait for SYNC (halts CPU until end of scanline) sta VSYNC ; Accumulator D1=1, turns on Vertical Sync signal sta WSYNC ; Wait for Sync - halts CPU until end of 1st scanline of VSYNC sta WSYNC ; wait until end of 2nd scanline of VSYNC lda #0 ; LoaD Accumulator with 0 so D1=0 sta WSYNC ; wait until end of 3rd scanline of VSYNC sta VSYNC ; Accumulator D1=0, turns off Vertical Sync signal rts ; ReTurn from Subroutine
Currently there's no game logic, so the VerticalBlank just waits for the 37 scanlines to pass:
VerticalBlank: ldx #37 ; LoaD X with 37 vbLoop: sta WSYNC ; Wait for SYNC (halts CPU until end of scanline) dex ; DEcrement X by 1 bne vbLoop ; Branch if Not Equal to 0 rts ; ReTurn from Subroutine
The Kernel is the section of code that draws the screen.
Kernel: ; turn on the display sta WSYNC ; Wait for SYNC (halts CPU until end of scanline) lda #0 ; LoaD Accumulator with 0 so D1=0 sta VBLANK ; Accumulator D1=1, turns off Vertical Blank signal (image output on) ; draw the screen ldx #192 ; Load X with 192 KernelLoop: sta WSYNC ; Wait for SYNC (halts CPU until end of scanline) stx COLUBK ; STore X into TIA's background color register dex ; DEcrement X by 1 bne KernelLoop ; Branch if Not Equal to 0 rts ; ReTurn from Subroutine
For this initial build it just changes the background color so we can see that we're generating a stable picture
Like Vertical Blank, OverScan doesn't have anything to do besides turning off the image output, so it just waits for enough scanlines to pass so that the total scanline count is 262.
OverScan: sta WSYNC ; Wait for SYNC (halts CPU until end of scanline) lda #2 ; LoaD Accumulator with 2 so D1=1 sta VBLANK ; STore Accumulator to VBLANK, D1=1 turns image output off ldx #27 ; LoaD X with 27 osLoop: sta WSYNC ; Wait for SYNC (halts CPU until end of scanline) dex ; DEcrement X by 1 bne osLoop ; Branch if Not Equal to 0 rts ; ReTurn from Subroutine
Anyway, download the source and take a look - there's comments galore.
Stella Programmer's Guide
Stella Programmers Guide.pdf (754.4KB)
Addendum on Keynote - what the audience sees:
What I see on the iPad: