# Visual Basic > Games and Graphics Programming > Game Demos >  Atari 2600 Programming Tutorial 3 - The Playfield (Demo Included)

## Jacob Roman

Welcome back to another exciting episode of my ultimate Atari 2600 programming tutorial.  :big yellow: 

Now things are gonna get interesting because now you are gonna get to plot pixels on the screen! Just one problem though. This one is a pain in the neck because the Atari was designed as a Pong-like system with cutting costs in mind. Even though there are 160 color clocks per visible scanline, there are only 40 pixels across the screen, with every pixel being 4x1 pixels wide. So the dimensions of the draw field pixels are 40x192. Thats why everything in Atari 2600 games looks so wide.

As for the playfield itself, there are 3 registers. PF0, PF1, and PF2. They only cover half the screen and is mirrored on the other side. PF0 is only 4 pixels wide, PF1 is 8 pixels wide, and PF2 is 8 pixels wide. So if you do the math, 4+8+8 + 4+8+8 = 40 pixels. Even though PF0 is 8 bits, the lower 4 bits are completely ignored by the processor. Any bits that are set will plot the pixels on the screen and mirror it on the other side. But it gets even worse.  PF0 and PF2's bits are reveresed! For example if PF0 is 00010000, with the lower 4 bits ignored, and the upper 4 bits reversed, it will draw a pixel on the left side of the screen using 1000. So you can imagine games with scrolling being extremely difficult to program on this beast with not only PF0 and PF2's bits being reversed, but also mirrored on the other side!

The mirroring can be turned on and off as well with the first bit of CTRLPF.

*Mirroring On:*


```
	lda #%00000001
	sta CTRLPF
```


*Mirroring Off:*


```
	lda #%00000000
	sta CTRLPF
```

What that does if the mirroring is on is that the left half of the screen becomes PF0, PF1, PF2 and the right half becomes PF2, PF1, PF0. If the mirroring is off, it becomes PF0, PF1, PF2, and PF0, PF1, PF2.

But the bits are more than for just mirroring. Take a look at what the other bits do!



```
CTRLPF

     This address is used to write into the playfield control

     register (a logic 1 causes action as described below)



     D0 = REF (reflect playfield)



     D1 = SCORE (left half of playfield gets color of player 0,

     right half gets color of player 1)



     D2 = PFP (playfield gets priority over players so they can

     move behind the playfield)



     D4 & D5 = BALL SIZE

               D5   D4   Width

               0    0    1 clock

               0    1    2 clocks

               1    0    4 clocks

               1    1    8 clocks
```

You can also set the color of the playfield through the COLUPF. For example:



```
	lda #$45
	sta COLUPF
```

This will set the color for the entire playfield to maroon red. 

Now that you got the basics of what a playfield is, it's time to do some code to draw a playfield! In this example we will be drawing a border all around the screen with a blue background:



```
	processor 6502

	include "vcs.h"
	include "macro.h"
	

BLUE         = $9A
	
;------------------------------------------------------------------------------
	SEG
	ORG $F000
	
Reset
; Clear RAM and all TIA registers
	ldx #0 
	lda #0 
Clear           
	sta 0,x 
	inx 
	bne Clear
;------------------------------------------------
; Once-only initialization. . .
	lda #BLUE
	sta COLUBK             ; set the background color
	
	lda #$45
	sta COLUPF
	
	lda #%00000001
	sta CTRLPF
	
;------------------------------------------------

StartOfFrame
; Start of new frame
; Start of vertical blank processing
	lda #0
	sta VBLANK
	lda #2
	sta VSYNC
	sta WSYNC
	sta WSYNC
	sta WSYNC               ; 3 scanlines of VSYNC signal
	lda #0
	sta VSYNC
;------------------------------------------------
; 37 scanlines of vertical blank. . .
	ldx #0
VerticalBlank   
	sta WSYNC
	inx
	cpx #37
	bne VerticalBlank
;------------------------------------------------
; Do 192 scanlines of color-changing (our picture)
      ldx #0                 ; this counts our scanline number
      lda #%11111111
      sta PF0
      sta PF1
      sta PF2
      ; We won't bother rewriting PF0-PF2 every scanline of the top 8 lines - they never change!

Top8Lines       
	sta WSYNC
    inx
    cpx #8                 ; are we at line 8?
    bne Top8Lines          ; No, so do another

    ; Now we want 176 lines of "wall"
    ; Note: 176 (middle) + 8 (top) + 8 (bottom) = 192 lines

    lda #%00010000         ; PF0 is mirrored <--- direction, low 4 bits ignored
    sta PF0
    lda #0
    sta PF1
    sta PF2
    ; again, we don't bother writing PF0-PF2 every scanline - they never change!

MiddleLines     
	sta WSYNC
    inx
    cpx #184
    bne MiddleLines
    ; Finally, our bottom 8 scanlines - the same as the top 8
    ; AGAIN, we aren't going to bother writing PF0-PF2 mid scanline!
    lda #%11111111
    sta PF0
    sta PF1
    sta PF2

Bottom8Lines    
	sta WSYNC
    inx
    cpx #192
    bne Bottom8Lines
;------------------------------------------------
    lda #%01000010
    sta VBLANK          ; end of screen - enter blanking      
;------------------------------------------------
; 30 scanlines of overscan. . .
	ldx #0
Overscan        
	sta WSYNC
	inx
	cpx #30
	bne Overscan
	jmp StartOfFrame
;------------------------------------------------------------------------------

	ORG $FFFA
	
InterruptVectors
	.word Reset          ; NMI
	.word Reset          ; RESET
	.word Reset          ; IRQ

END
```

Save the file as playfield.asm, and change the Compile.bat code to this:



```
@echo off
dasm playfield.asm -lkernel.txt -f3 -v5 -oplayfield.bin
```

Be sure its all in the same folder as the DASM.exe so it can compile! Run the batch file to compile the playfield.asm code. You should have a playfield.bin file created. Run it through Stella and it should look like this:



And that's how it's done! You can play around with where the pixels are plotted if you'd like, or even change the colors of everything.

*Exercise:* Remove the right wall while having the left wall remain!

_Answer to Tutorial 2 exercise:_


```
	processor 6502

	include "vcs.h"
	include "macro.h"

BLACK         = $00
	
;------------------------------------------------------------------------------
	SEG
	ORG $F000
	
Reset
; Clear RAM and all TIA registers
	ldx #0 
	lda #0 
Clear           
	sta 0,x 
	inx 
	bne Clear
;------------------------------------------------
; Once-only initialization. . .
	lda #BLACK
	sta COLUBK             ; set the background color
;------------------------------------------------

StartOfFrame
; Start of new frame
; Start of vertical blank processing
	lda #0
	sta VBLANK
	lda #2
	sta VSYNC
	sta WSYNC
	sta WSYNC
	sta WSYNC               ; 3 scanlines of VSYNC signal
	lda #0
	sta VSYNC
;------------------------------------------------
; 37 scanlines of vertical blank. . .
	ldx #0
VerticalBlank   
	sta WSYNC
	inx
	cpx #37
	bne VerticalBlank
;------------------------------------------------
;192 lines of drawfield
        ldx #0
DrawField:

	sta WSYNC
        inx
	stx COLUBK
	cpx #192
	bne DrawField
;------------------------------------------------
; end of screen - enter blanking
        lda #%01000010
        sta VBLANK          
;------------------------------------------------
; 30 scanlines of overscan. . .
	ldx #0
Overscan        
	sta WSYNC
	inx
	cpx #30
	bne Overscan
	jmp StartOfFrame
;------------------------------------------------

	ORG $FFFA
	
InterruptVectors
	.word Reset          ; NMI
	.word Reset          ; RESET
	.word Reset          ; IRQ

END
```

Next tutorial I'm gonna show you how to do real graphics through asymmetrical playfields  :Smilie:

----------

