Created
March 30, 2015 21:17
-
-
Save safiire/66746adc460abad3a429 to your computer and use it in GitHub Desktop.
NES sound demo from my blog post.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;;;; | |
; Create an iNES header | |
.ines {"prog": 1, "char": 0, "mapper": 0, "mirror": 0} | |
;;;; | |
; Include all the symbols in the nes library | |
.inc <nes.sym> | |
;;;; | |
; Open the prog section bank 0 | |
.segment prog 0 | |
;;;; | |
; Structure to keep track of input | |
.org $0000 | |
.scope controller_state | |
.space b 1 | |
.space a 1 | |
. | |
;;;; | |
; Setup the interrupt vectors | |
.org $FFFA | |
.dw vblank | |
.dw reset | |
.dw irq | |
;;;; | |
; Here is our code entry point | |
.org $C000 | |
.scope reset | |
sei ; SEt Interrupt (Disables them) | |
cld ; CLear Decimal Mode | |
ldx #$ff | |
txs ; Set the stack pointer | |
ldx #$00 | |
stx nes.ppu.control | |
stx nes.ppu.mask ; Disable Vblank & Rendering | |
jsr zero_apu ; Zero all APU registers | |
; We need to wait for at least 2 Vblanks to happen | |
; before we know the PPU has stabilized at startup | |
; Here we wait for the first one. | |
wait_vblank1: | |
bit nes.ppu.status | |
bpl wait_vblank1 | |
; Before we wait for the second vblank, lets | |
; zero all of the working RAM $0 to $800 | |
; The $200s are sprite OAM, and should be set to $ff | |
clear_ram: | |
lda #$00 | |
sta $00, x | |
sta $100, x | |
sta $300, x | |
sta $400, x | |
sta $500, x | |
sta $600, x | |
sta $700, x | |
lda #$ff | |
sta $200, x | |
inx | |
bne clear_ram | |
; Now wait for the second vblank | |
wait_vblank2: | |
bit nes.ppu.status | |
bpl wait_vblank2 | |
jsr initialize | |
forever: | |
jmp forever | |
rti | |
. | |
;;;; | |
; Initialize everything | |
.scope initialize | |
; Enable pulse1 and pulse2 in the APU | |
lda #%00000011 | |
sta nes.apu.channel_enable | |
; Initialize the controller states | |
lda #$00 | |
sta controller_state.a zp | |
sta controller_state.b zp | |
; Reenable interrupts, Turn Vblank back on | |
lda #%10000000 | |
sta nes.ppu.control | |
cli | |
rts | |
. | |
;;;; | |
; VBlank is called 60 times per second | |
.scope vblank | |
jsr read_input | |
rti | |
. | |
;;;; | |
; IRQ, we are not using | |
.scope irq | |
rti | |
. | |
;;;; | |
; Zero all the APU registers | |
.scope zero_apu | |
lda #$00 | |
ldx #$00 | |
loop: | |
sta $4000, x | |
inx | |
cpx $18 | |
bne loop | |
rts | |
. | |
;;;; | |
; Read input from controller 1 | |
.scope read_input | |
lda #$01 ; strobe joypad | |
sta nes.controller1 | |
lda #$00 | |
sta nes.controller1 | |
; Handle Button A | |
lda nes.controller1 | |
and #$01 | |
beq update_a_state | |
; A is pressed, but did it just change to being pressed now? | |
ldx controller_state.a zp | |
bne update_a_state | |
; do the thing A does | |
jsr play_a440 | |
update_a_state: | |
sta controller_state.a zp | |
; Handle Button B | |
lda nes.controller1 | |
and #$01 | |
beq update_b_state | |
; B is pressed, but did it just change to being pressed now? | |
ldx controller_state.b zp | |
bne update_b_state | |
; Do the thing B does | |
jsr play_a220 | |
update_b_state: | |
sta controller_state.b zp | |
rts | |
. | |
;;;; | |
;; This will play an A 220hz note | |
;; On the pulse1 generator | |
.scope play_a220 | |
pha | |
lda #%10011111 | |
sta nes.apu.pulse1.control | |
lda #%11111011 | |
sta nes.apu.pulse1.ft | |
lda #%11111001 | |
sta nes.apu.pulse1.ct | |
pla | |
rts | |
. | |
;;;; | |
;; This will play an A 220hz note | |
;; On the pulse2 generator | |
.scope play_a440 | |
pha | |
lda #%10011111 | |
sta nes.apu.pulse2.control | |
lda #%11111101 | |
sta nes.apu.pulse2.ft | |
lda #%11111000 | |
sta nes.apu.pulse2.ct | |
pla | |
rts | |
. | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment