# Visual Basic > Games and Graphics Programming > Game Demos >  NES 6502 Programming Tutorial - Part 5: Controller Commands

## Jacob Roman

Hey and welcome back to my NES 6502 programming tutorial. Today I'm going to show you how to move the sprite using the controller. The NES controller, as you see here, has eight buttons:



which obviously consists of up, down, left, right, B, A, select, and start. And the NES has two controller ports. But believe it or not, some NES games have 4 player simultaneous play requiring four controllers, which is only possible if you have an NES Four Score or an NES Satellite:



And there are too many peripherals to count, such as the Zapper, the Power Pad, the Miracle Piano, R.O.B. the Robot, the Power Glove, etc. All of which use different states the controller ports read besides the basic eight. So in this tutorial, I'm only going to focus on Controller 1 which reads at the address $4016. If you wanna attempt Controller 2 in the mix, it's at address $4017. So we are going to rework our Sprite Movement project and change up a couple of things.

The first step is that we are going to need to latch both the controllers right after the small chunk of code in the NMI:



```
NMI:
  LDA #$00
  STA $2003       ; set the low byte (00) of the RAM address
  LDA #$02
  STA $4014       ; set the high byte (02) of the RAM address, start the transfer

LatchController:
  LDA #$01
  STA $4016
  LDA #$00
  STA $4016       ; tell both the controllers to latch buttons
```

Next, we will need to read the memory address $4016 in this exact order and check if there has been an input pressed, and remember, it is in this exact order!

 (1) A (2) B (3) Select (4) Start (5) Up (6) Down (7) Left (8) Right

As an example, we will proceed directly after the LatchController code starting with A for simplicity:



```
LatchController:
  LDA #$01
  STA $4016
  LDA #$00
  STA $4016       ; tell both the controllers to latch buttons

ReadA: 
  LDA $4016       ; player 1 - A
  AND #%00000001  ; only look at bit 0
  BEQ ReadADone   ; branch to ReadADone if button is NOT pressed (0)
                  ; add instructions here to do something when button IS pressed (1)

ReadADone:        ; handling this button is done
```

Basically, any action you want to happen when the button is pressed goes in between the BEQ and the subroutine ReadADone. Otherwise it jumps when it is not pressed. And it will continue on to the other buttons in that specific order. So basically, you are adding all this:



```
LatchController:
  LDA #$01
  STA $4016
  LDA #$00
  STA $4016       ; tell both the controllers to latch buttons

ReadA: 
  LDA $4016       ; player 1 - A
  AND #%00000001  ; only look at bit 0
  BEQ ReadADone   ; branch to ReadADone if button is NOT pressed (0)
                  ; add instructions here to do something when button IS pressed (1)

ReadADone:        ; handling this button is done
  
ReadB: 
  LDA $4016       ; player 1 - B
  AND #%00000001  ; only look at bit 0
  BEQ ReadBDone   ; branch to ReadBDone if button is NOT pressed (0)
                  ; add instructions here to do something when button IS pressed (1)

ReadBDone:        ; handling this button is done

ReadSelect: 
  LDA $4016       ; player 1 - A
  AND #%00000001  ; only look at bit 0
  BEQ ReadSelectDone   ; branch to ReadADone if button is NOT pressed (0)

ReadSelectDone:

ReadStart: 
  LDA $4016       ; player 1 - A
  AND #%00000001  ; only look at bit 0
  BEQ ReadStartDone   ; branch to ReadADone if button is NOT pressed (0)

ReadStartDone:

ReadUp: 
  LDA $4016       ; player 1 - A
  AND #%00000001  ; only look at bit 0
  BEQ ReadUpDone   ; branch to ReadADone if button is NOT pressed (0)

ReadUpDone:

ReadDown: 
  LDA $4016       ; player 1 - A
  AND #%00000001  ; only look at bit 0
  BEQ ReadDownDone   ; branch to ReadADone if button is NOT pressed (0)

ReadDownDone:

ReadLeft: 
  LDA $4016       ; player 1 - A
  AND #%00000001  ; only look at bit 0
  JMP ReadLeftDone   ; branch to ReadADone if button is NOT pressed (0)

ReadLeftDone:

ReadRight: 
  LDA $4016       ; player 1 - A
  AND #%00000001  ; only look at bit 0
  JMP ReadRightDone ; branch to ReadADone if button is NOT pressed (0)

ReadRightDone:

```

In your sprite movement project, you had a chunk of code to automatically move Mario across the screen towards the right. Go ahead and copy and paste this chunk here that you had:



```
  LDA player_x
  STA $0203
  STA $020B
  TAX
  CLC
  ADC #$08
  STA $0207
  STA $020F
  INX
  STX player_x
```

And put it inside the controls for the Right:



```
ReadRight: 
  LDA $4016       ; player 1 - A
  AND #%00000001  ; only look at bit 0
  JMP ReadRightDone ; branch to ReadADone if button is NOT pressed (0)


;Move Mario to the right  
  LDA player_x
  STA $0203
  STA $020B
  TAX
  CLC
  ADC #$08
  STA $0207
  STA $020F
  INX
  STX player_x
  
ReadRightDone:
```

Compile the code using either the batch file, or dragging the asm file into NESASM3, and run it in your emulator. DOH! It's not moving. Looks like we left something out. If the AND result is not equal, well need to jump to the movement code:



```
ReadRight: 
  LDA $4016       ; player 1 - A
  AND #%00000001  ; only look at bit 0
  BNE DoRight
  JMP ReadRightDone ; branch to ReadADone if button is NOT pressed (0)

;Move Mario to the right  
DoRight:
  LDA player_x
  STA $0203
  STA $020B
  TAX
  CLC
  ADC #$08
  STA $0207
  STA $020F
  INX
  STX player_x
  
ReadRightDone:
```

Now recompile it, and run it. Now Mario moves right....and only right  :Sick: . Well need some code to move him left as well:



```
ReadLeft: 
  LDA $4016       ; player 1 - A
  AND #%00000001  ; only look at bit 0
  BNE DoLeft
  JMP ReadLeftDone   ; branch to ReadADone if button is NOT pressed (0)

;Move Mario to the left
DoLeft:
  LDA player_x
  STA $0203
  STA $020B
  TAX
  CLC
  ADC #$08
  STA $0207
  STA $020F
  DEX
  STX player_x  
  
ReadLeftDone:
```

Compile and run the code again, and now Mario moves left and right seamlessly. By now your completed code looks like this:



```
  .inesprg 1   ; 1x 16KB PRG code
  .ineschr 1   ; 1x  8KB CHR data
  .inesmap 0   ; mapper 0 = NROM, no bank swapping
  .inesmir 1   ; background mirroring
  
;;;;;;;;;;;;;;;
;; DECLARE SOME VARIABLES HERE
  .rsset $0000  ;;start variables at ram location 0
  
player_x  .rs 1  ; .rs 1 means reserve one byte of space  
;;;;;;;;;;;;;;;

  .bank 0
  .org $C000 
RESET:
  SEI          ; disable IRQs
  CLD          ; disable decimal mode
  LDX #$40	
  STX $4017    ; disable APU frame IRQ
  LDX #$FF	
  TXS          ; Set up stack
  INX          ; now X = 0
  STX $2000    ; disable NMI
  STX $2001    ; disable rendering
  STX $4010    ; disable DMC IRQs

vblankwait1:       ; First wait for vblank to make sure PPU is ready
  BIT $2002
  BPL vblankwait1

clrmem:
  LDA #$00
  STA $0000, x
  STA $0100, x
  STA $0400, x
  STA $0500, x
  STA $0600, x
  STA $0700, x
  LDA #$FE
  STA $0300, x
  INX
  BNE clrmem
   
vblankwait2:      ; Second wait for vblank, PPU is ready after this
  BIT $2002
  BPL vblankwait2
  
LoadPalette:
  LDA $2002             ; read PPU status to reset the high/low latch
  LDA #$3F
  STA $2006             ; write the high byte of $3F00 address
  LDA #$00
  STA $2006             ; write the low byte of $3F00 address
  LDX #$00              ; start out at 0
LoadBackgroundPaletteLoop:
  LDA background_palette, x        ; load data from address (palette + the value in x)
                          ; 1st time through loop it will load palette+0
                          ; 2nd time through loop it will load palette+1
                          ; 3rd time through loop it will load palette+2
                          ; etc
  STA $2007             ; write to PPU
  INX                   ; X = X + 1
  CPX #$10              ; Compare X to hex $10, decimal 16
  BNE LoadBackgroundPaletteLoop  ; Branch to LoadBackgroundPaletteLoop if compare was Not Equal to zero
  
  LDX #$00      
        
LoadSpritePaletteLoop:
  LDA sprite_palette, x     ;load palette byte
  STA $2007					;write to PPU
  INX                   	;set index to next byte
  CPX #$10            
  BNE LoadSpritePaletteLoop  ;if x = $10, all done

  LDX #$00              ; start at 0
LoadSpritesLoop:
  LDA sprites, x        ; load data from address (sprites +  x)
  STA $0200, x          ; store into RAM address ($0200 + x)
  INX                   ; X = X + 1
  CPX #$10              ; Compare X to hex $10, decimal 16
  BNE LoadSpritesLoop   ; Branch to LoadSpritesLoop if compare was Not Equal to zero
                        ; if compare was equal to 32, keep going down 
  
  LDA #%10000000   ; enable NMI, sprites from Pattern Table 0
  STA $2000
  
  LDA #%00010000   ; enable sprites
  STA $2001
  
  LDA $0203
  STA player_x

Foreverloop:
  JMP Foreverloop     ;jump back to Forever, infinite loop

NMI: 
  LDA #$00
  STA $2003       ; set the low byte (00) of the RAM address
  LDA #$02
  STA $4014       ; set the high byte (02) of the RAM address, start the transfer
  
LatchController:
  LDA #$01
  STA $4016
  LDA #$00
  STA $4016       ; tell both the controllers to latch buttons

ReadA: 
  LDA $4016       ; player 1 - A
  AND #%00000001  ; only look at bit 0
  BEQ ReadADone   ; branch to ReadADone if button is NOT pressed (0)
                  ; add instructions here to do something when button IS pressed (1)

ReadADone:        ; handling this button is done
  
ReadB: 
  LDA $4016       ; player 1 - B
  AND #%00000001  ; only look at bit 0
  BEQ ReadBDone   ; branch to ReadBDone if button is NOT pressed (0)
                  ; add instructions here to do something when button IS pressed (1)

ReadBDone:        ; handling this button is done

ReadSelect: 
  LDA $4016       ; player 1 - A
  AND #%00000001  ; only look at bit 0
  BEQ ReadSelectDone   ; branch to ReadADone if button is NOT pressed (0)

ReadSelectDone:

ReadStart: 
  LDA $4016       ; player 1 - A
  AND #%00000001  ; only look at bit 0
  BEQ ReadStartDone   ; branch to ReadADone if button is NOT pressed (0)

ReadStartDone:

ReadUp: 
  LDA $4016       ; player 1 - A
  AND #%00000001  ; only look at bit 0
  BEQ ReadUpDone   ; branch to ReadADone if button is NOT pressed (0)

ReadUpDone:

ReadDown: 
  LDA $4016       ; player 1 - A
  AND #%00000001  ; only look at bit 0
  BEQ ReadDownDone   ; branch to ReadADone if button is NOT pressed (0)

ReadDownDone:

ReadLeft: 
  LDA $4016       ; player 1 - A
  AND #%00000001  ; only look at bit 0
  BNE DoLeft
  JMP ReadLeftDone   ; branch to ReadADone if button is NOT pressed (0)

;Move Mario to the left 
DoLeft:
  LDA player_x
  STA $0203
  STA $020B
  TAX
  CLC
  ADC #$08
  STA $0207
  STA $020F
  DEX
  STX player_x  
  
ReadLeftDone:

ReadRight: 
  LDA $4016       ; player 1 - A
  AND #%00000001  ; only look at bit 0
  BNE DoRight
  JMP ReadRightDone ; branch to ReadADone if button is NOT pressed (0)

;Move Mario to the right  
DoRight:
  LDA player_x
  STA $0203
  STA $020B
  TAX
  CLC
  ADC #$08
  STA $0207
  STA $020F
  INX
  STX player_x
  
ReadRightDone:

  RTI

;;;;;;;;;;;;;;  

  .bank 1
  .org $E000
background_palette:
  .db $22,$29,$1A,$0F	;background palette 1
  .db $22,$36,$17,$0F	;background palette 2
  .db $22,$30,$21,$0F	;background palette 3
  .db $22,$27,$17,$0F	;background palette 4
  
sprite_palette:
  .db $22,$16,$27,$18	;sprite palette 1
  .db $22,$1A,$30,$27	;sprite palette 2
  .db $22,$16,$30,$27	;sprite palette 3
  .db $22,$0F,$36,$17	;sprite palette 4
  
sprites:
     ;vert tile attr horiz
  .db $08, $3A, %00000000, $08   ;sprite 0
  .db $08, $37, %00000000, $10   ;sprite 1
  .db $10, $4f, %00000000, $08   ;sprite 2
  .db $10, $4f, %01000000, $10   ;sprite 3


;;;;;;;;;;;;;;  

  .org $FFFA     ;first of the three vectors starts here
  .dw NMI        ;when an NMI happens (once per frame if enabled) the 
                   ;processor will jump to the label NMI:
  .dw RESET      ;when the processor first turns on or is reset, it will jump
                   ;to the label RESET:
  .dw 0          ;external interrupt IRQ is not used in this tutorial
  
;;;;;;;;;;;;;;  

  .bank 2
  .org $0000
  .incbin "mario.chr"   ;includes 8KB graphics file from SMB1
```

For an added challenge, try moving Mario up and down as well! I haven't decided what I want to do for my next tutorial yet, but maybe I might touch into drawing background tiles, since animation is too advanced of a jump for you noobies. But I'll eventually get to it. Have an awesome day!  :big yellow: 

[EDIT] For more advanced controller tricks, I found this on NESWiki: https://wiki.nesdev.com/w/index.php/Controller_Reading

----------

