I posted some info about a custom controller I made called the DrumAxe in the hardware section of this forum:
http://nesdev.com/bbs/viewtopic.php?t=4244
Most of this code was given to me by people like Blargg, Tepples, Celius, Disch, and Tokumaru.
Some people have mentioned possible enhancing/improving, modifying the code so I will post here so that if that happens we might learn from it.
Code:
;Nes Gamepad demo program 4/28/08
;-------------------
; INES header setup
.inesprg 1
.ineschr 0 ; zero because we don't have character data
.inesmir 1
.inesmap 0
.bank 1
.org $FFFA
.dw 0 ; NMI routine
.dw start ; Reset routine
.dw 0 ; IRQ routine
.bank 0
.org $8000
start:
key_a EQU %00000001 ; A button press
key_b EQU %00000010 ; B
key_select EQU %00000100 ; select
key_start EQU %00001000 ; start
key_up EQU %00010000 ; up arrow
key_down EQU %00100000 ; down
key_left EQU %01000000 ; left arrow
key_right EQU %10000000 ; right
ab_pressed EQU %00000011 ; A and B are pressed
button_state EQU $00
button_state2 EQU $0F
sei ; ignore 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:
bit $2002
bpl vblankwait1
; We now have about 30,000 cycles to burn before the PPU stabilizes.
; Use it to clear RAM. X is still 0...
txa
clrmem: ; this is for the video stuff
sta $000,x
sta $100,x
sta $200,x
sta $300,x
sta $400,x
sta $500,x
sta $600,x
sta $700,x ; Remove this if you're storing reset-persistent data
inx
bne clrmem
vblankwait2:
bit $2002
bpl vblankwait2
; *** CLEAR SOUND REGISTERS ***
lda #$00 ; clear all the sound registers by setting
ldx #$00 ; everything to 0 in the Clear_Sound loop
Clear_Sound:
sta $4000,x ; store accumulator at $4000 offset by x
inx ; increment x
cpx #$0F ; compare x to $0F
bne Clear_Sound ; branch back to Clear_Sound if x != $0F
lda #$10 ; load accumulator with $10
sta $4010 ; store accumulator in $4010
lda #$00 ; load accumulator with 0
sta $4011 ; clear these 3 registers that are
sta $4012 ; associated with the delta modulation
sta $4013 ; channel of the NES
loop:
jsr updatejoy
;Check the state of the right key
lda button_state
and #key_right
beq right_not_pressed
jsr right_is_pressed
right_not_pressed:
;Check the state of the left button
lda button_state
and #key_left
beq left_not_pressed
jsr left_is_pressed
left_not_pressed:
;Check the state of the up arrow
lda button_state
and #key_up
beq up_not_pressed
jsr up_is_pressed
up_not_pressed:
;Check the state of the downss arrow
lda button_state
and #key_down
beq down_not_pressed
jsr down_is_pressed
down_not_pressed:
;Check if A and B are pressed
lda button_state
AND #$03 ; mask out A+B bits
CMP #$03 ; see if it equals A+B
BNE ab_not_pressed
jsr ab_is_pressed
ab_not_pressed:
;Check if A is pressed
lda button_state
AND #key_a ; mask out bits
BEQ a_not_pressed
jsr a_is_pressed
a_not_pressed:
;Check if b button is pressed
lda button_state
and #key_b
beq b_not_pressed
jsr b_is_pressed
b_not_pressed:
;Check if select button is pressed
lda button_state
and #key_select
beq select_not_pressed
jsr select_is_pressed
select_not_pressed:
;Check if start button is pressed
lda button_state
and #key_start
beq start_not_pressed
jsr start_is_pressed
start_not_pressed:
;Check State of Right Button of Joypad #2
lda button_state2
and #key_right
beq right_not_pressed_2
jsr right_is_pressed_2
right_not_pressed_2:
;check state of A button of joypad #2
lda button_state2
AND #key_a ; mask out bits
BEQ a_not_pressed_2
jsr a_is_pressed_2
a_not_pressed_2:
;Check state of b button on joypad #2
lda button_state2
and #key_b
beq b_not_pressed_2
jsr b_is_pressed_2
b_not_pressed_2:
;Check the state of the left button of joypad #2
lda button_state2
and #key_left
beq left_not_pressed_2
jsr left_is_pressed_2
left_not_pressed_2:
;Check the state of the up arrow of joypad #2
lda button_state2
and #key_up
beq up_not_pressed_2
jsr up_is_pressed_2
up_not_pressed_2:
;Check the state of the up arrow of joypad #3
lda button_state2
and #key_down
beq down_not_pressed_2
jsr down_is_pressed_2
down_not_pressed_2:
;Check if select button is pressed
lda button_state2
and #key_select
beq select_not_pressed_2
jsr select_is_pressed_2
select_not_pressed_2:
jmp loop ;Go back and keep reading the joypad forever
updatejoy:
LDA #1 ; strobe joypad 1
STA $4016
LDA #0
STA $4016
LDX #$08 ; set X to 8 (the number of times we want to loop, once fo each button)
joybuttons:
LDA $4016 ; get button state
LSR A ; shift it into the C flag
ROR button_state ; rotate C flag into our button_state variable
DEX ; decrement X (our loop counter)
BNE joybuttons ; jump back to our loop until X is zero
; Begin reading joypad #2 and store bits in button_state2 variable.
LDY #$08
joybuttons2:
LDA $4017 ; get button state
LSR A ; shift it into the C flag
ROR button_state2 ; rotate C flag into our button_state variable
DEY ; decrement X (our loop counter)
BNE joybuttons2 ; jump back to our loop until Y is zero
rts
right_is_pressed: ; play sound when right arrow is pressed.
lda #$0F ; Enable channels
sta $4015
lda #%00111101 ; mode, period
sta $400E
lda #%0000000 ; duration
sta $400F
rts
left_is_pressed:
lda #$0F ; Enable channels
sta $4015
lda #%00010101 ; mode, period
sta $400E
lda #%10000000 ; duration
sta $400F
rts
up_is_pressed:
lda #$0F ; Enable channels
sta $4015
lda #%00111111 ; mode, period low rumble
sta $400E
lda #%0000000 ; duration
sta $400F
rts
down_is_pressed:
lda #$0F ; Enable channels
sta $4015
lda #%00111110 ; mode, period
sta $400E
lda #%11111000 ; duration
sta $400F
rts
a_is_pressed:
lda #$0F ; Enable channels
sta $4015
lda #%00010111 ; mode, period
sta $400E
lda #%10000000 ; duration
sta $400F
rts
b_is_pressed:
lda #$0F ; Enable channels
sta $4015
lda #%01011011 ; mode, period low rumble
sta $400E
lda #%00000000 ; duration
sta $400F
rts
select_is_pressed:
lda #$0F ; Enable channels
sta $4015
lda #%10111011 ; mode, period
sta $400E
lda #%10101111 ; duration
sta $400F
rts
start_is_pressed:
lda #$0F ; Enable channels
sta $4015
lda #%11000011 ; mode, period
sta $400E
lda #%10101001 ; duration
sta $400F
rts
ab_is_pressed:
rts
;JoyPad #2 subroutines below
right_is_pressed_2:
lda #$0F ; Enable channels
sta $4015
lda #%00100011 ; enable medium looping with a 1 at bit 5
sta $400C
rts
left_is_pressed_2:
lda #$0F ; Enable channels
sta $4015
lda #%00100111 ; enable medium/slow looping with a 1 at bit 5
sta $400C
rts
up_is_pressed_2:
lda #$0F ; Enable channels
sta $4015
lda #%00100001 ; enable fast looping with a 1 at bit 5
sta $400C
rts
down_is_pressed_2:
lda #$0F ; Enable channels
sta $4015
lda #%00101111 ; enable slow looping
sta $400C
rts
a_is_pressed_2:
rts
b_is_pressed_2:
rts
start_is_pressed_2:
rts
select_is_pressed_2:
jsr start ; Resets sound to the beginning, clears sound registers:(Stops the volume decay loop).
rts