Here is the code. It's very simple since I am just a beginner with NES programming.
If anyone wants to do anything to it, I thought we can repost this code in the newbie section and continue "stepwise" so the changes, enhancements, mods to the code can be taught to newbies like me.
My custom controller, the DrumAxe just replaces one of the gamepads, each sensor on the DrumAxe corresponds to a button on gamepad #1. Gamepad #2 can be used to create pulsing effects.
Would be nice to explore the other sound channels. I'm not claiming any exclusive rights to any of this code. Most of this code was spoon fed to me in the newbie section back in Feb-April. If no one has any objections, I'm humbly proposing that it can be shared and used as anyone wishes, freely open.
If anyone wants details of the DrumAxe circuit let me know, it's really a simple device.
(I will also post this in the newbie section, and we'll continue the thread there, instead of here.)
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