ASM6 - JSR's not doing anything

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

Post Reply
BARBEERIAN
Posts: 13
Joined: Sun Jan 02, 2011 9:58 pm

ASM6 - JSR's not doing anything

Post by BARBEERIAN » Mon Jan 21, 2019 9:57 am

So I'm going through the Nerdy Nights tutorials (the version for ASM6) and I was trying to move parts of my code into subroutines to make things cleaner, easier to read, and a little more object oriented. For some reason the subroutines don't execute, but if I manually put my code where the JSR calls are made it works just fine. It compiles just fine either way, and I can't figure out what I'm doing wrong. Any help would be appreciated.

Here's the main chunk of the program:

Code: Select all

;********** Header ****************************************

byte "NES",$1a			;"NES" plus a terminator
byte $01				;1x16Kb Program ROM block ($C000)
byte $01				;1x8Kb Character ROM block
byte $00				;don't care
byte $00				;don't care
dsb 8					;8 bytes padding

;********** Program Code ****************************************
	.org $C000

vblankWait:			;vblankWait - waits for Vblank (NMI)
	BIT $2002
	BPL vblankWait
	RTS
	
clearMem:			;Clears memory to get ready to start game
	LDA #$00
	STA $0000, x
	STA $0100, x
	STA $0200, x
	STA $0400, x
	STA $0500, x
	STA $0600, x
	STA $0700, x
	LDA #$FE
	STA $0300, x
	INX
	BNE clearMem	;Branch if not equal to zero
	RTS
	
loadPalettes:		;loads Palette data into $3F00
	LDA $2002		;read PPU status to reset the high/low latch
	LDA #$3F
	STA $2006		;write high byte of $3F00 address
	LDA #$00
	STA $2006		;write low byte of $3F00 address
	LDX #$00
loadPalettesLoop:
	LDA palette, x	;load data from address (palette + x)
	STA $2007
	INX
	CPX #$20		;Compare X to 32
	BNE loadPalettesLoop
	RTS
	
loadSprites:
	LDX #$00		;start at 0
loadSpritesLoop:
	LDA player1_sprite, x	;load data from address (player1_sprite + x)
	STA $0200, x			;store into RAM address ($0200 + x)
	INX
	CPX #$20				;Compare X to 32
	BNE loadSpritesLoop		;Branch if not equal to 0
	RTS
	
RESET:			;Reset Vector - Program execution starts here on Reset/PowerOn
	SEI				;Disable IRQs
	CLD				;disable Decimal mode
	LDX #$40		;load 0x40 (64) into X
	STX $4017		;store X into $4017, disables APU frame IRQ
	LDX #$FF		;load 0xFF (255) into X
	TXS				;transfer X to Stack, sets up stack
	INX				;increment X, X now = 0
	STX $2000		;disable NMI
	STX $2001		;disable rendering
	STX $4010		;disable DMC IRQs
	
	JSR vblankWait
	JSR clearMem
	JSR vblankWait
	JSR loadPalettes
	JSR loadSprites
	
;PPU CONTROL REGISTER SETUP
	;VPHB SINN - Bits to write to PPU Control register ($2000)
	;V = Vblank NMI enable
	;P = PPU Master/Slave select
	;S = Sprite Size. 0 = 8x8, 1 = 8x16
	;B = Background pattern table address. 0 = $0000, 1 = $1000
	;S = Sprite pattern table address for 8x8 sprites (ignored in 8x16 mode). 0 = $0000, 1 = $1000
	;I = Pattern table increment. 0 = Add 1 (going across), 1 = add 32 (going down)
	;NN = Base nametable address. 0 = $2000, 1 = $2400, 2 = $2800, 3 = $2C00
	LDA #%10000000		;enable NMI
	STA $2000			;Write to PPU Control register
	
;PPU MASK REGISTER SETUP
	;BGRs bMmG
	;B = emphasize blue
	;G = emphasize green
	;R = emphasize red
	;s = show sprites
	;b = show background
	;M = show sprites in leftmost margin (8 pixels)
	;m = show sprites in rightmost margin (8 pixels)
	;G = grayscale (0 = normal colour, 1 = grayscale)
	LDA #%00010000		;enable sprites
	STA $2001			;Write to PPU Mask register
	
MAIN:		;MAIN loop
	JMP MAIN

NMI:		;NMI - Vblank interrupt
	LDA #$00
	STA $2003	;set the low byte of the RAM address
	LDA #$02
	STA $4014	;set the high byte of the RAM address and start the transfer
	
	RTI			;Return from Interrupt

tepples
Posts: 21748
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: ASM6 - JSR's not doing anything

Post by tepples » Mon Jan 21, 2019 10:19 am

What happens if the NMI handler is called while something is using register A?

User avatar
tokumaru
Posts: 11465
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: ASM6 - JSR's not doing anything

Post by tokumaru » Mon Jan 21, 2019 10:24 am

You can't JSR to a subroutine that clears memory because it also clears the stack ($0100-$01FF), where the return addresses for subroutines are stored. Since you're wiping out the return address, the RTS will try to return to address $0000 (actually $0001, but that's irrelevant), and the program crashes.

BARBEERIAN
Posts: 13
Joined: Sun Jan 02, 2011 9:58 pm

Re: ASM6 - JSR's not doing anything

Post by BARBEERIAN » Mon Jan 21, 2019 10:34 am

tepples wrote:What happens if the NMI handler is called while something is using register A?
I don't think NMI would get called during those subroutines. Near the start of the code at the RESET vector it's turning NMI and rendering off before doing any of my subroutines. Register A isn't getting used at all before those are turned off, and it's getting loaded with relevant data during each subroutine.
tokumaru wrote:You can't JSR to a subroutine that clears memory because it also clears the stack ($0100-$01FF), where the return addresses for subroutines are stored. Since you're wiping out the return address, the RTS will try to return to address $0000 (actually $0001, but that's irrelevant), and the program crashes.
Ah okay that makes sense. Didn't know clearMem was also erasing the stack. Just tested it and it made clearMem not call to a subroutine (wrote it inline with the other stuff after RESET:) and it works great.

Thanks!

User avatar
dougeff
Posts: 2614
Joined: Fri May 08, 2015 7:17 pm
Location: DIGDUG
Contact:

Re: ASM6 - JSR's not doing anything

Post by dougeff » Mon Jan 21, 2019 11:35 am

Technically, you don't really need to zero the stack at all.
nesdoug.com -- blog/tutorial on programming for the NES

User avatar
tokumaru
Posts: 11465
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: ASM6 - JSR's not doing anything

Post by tokumaru » Mon Jan 21, 2019 1:09 pm

Technically, you don't really need to zero *any* memory at all.

If you initialize every variable before using them, as you should, clearing memory is redundant... Most people do it anyway, to be safe I guess.

lidnariq
Posts: 8768
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: ASM6 - JSR's not doing anything

Post by lidnariq » Mon Jan 21, 2019 5:16 pm

There could be merit, if you are testing with an emulator that randomizes memory, in not clearing all memory so that you can find situations where you aren't initializing memory. Fail fast.

But for a final build, there is no advantage in failing to clear memory at boot.

tepples
Posts: 21748
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: ASM6 - JSR's not doing anything

Post by tepples » Mon Jan 21, 2019 5:42 pm

Even better is an emulator that breaks on reading uninitialized memory. BGB, a Game Boy emulator, does this.

Pokun
Posts: 1269
Joined: Tue May 28, 2013 5:49 am
Location: Hokkaido, Japan

Re: ASM6 - JSR's not doing anything

Post by Pokun » Mon Jan 21, 2019 5:48 pm

Yeah and for example flashcarts may also leave uninitialized memory in a non-random state because the menu used RAM before the game loaded. In other words, not clearing RAM or relying on the randomness of RAM (like Final Fantasy 1 apparently does) may result in compatibility problems.


BTW, a nitpick but $2003 doesn't "set the low byte of RAM address", it selects OAM address ($00-$FF) for OAM access. If using OAM-DMA it should be set to 0, which you do correctly though. I suppose Nerdy Nights is "guilty" for this little misconception.

User avatar
tokumaru
Posts: 11465
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: ASM6 - JSR's not doing anything

Post by tokumaru » Mon Jan 21, 2019 5:55 pm

Pokun wrote:BTW, a nitpick but $2003 doesn't "set the low byte of RAM address", it selects OAM address ($00-$FF) for OAM access. If using OAM-DMA it should be set to 0, which you do correctly though. I suppose Nerdy Nights is "guilty" for this little misconception.
Yeah, that comment about "setting the low byte" shows up here every once in a while. I knew it came from some sort of tutorial, but was never sure which one.

As for clearing RAM or not, I'm not gonna argue about it anymore. I don't do it in my programs, because I find it redundant, but I'm OK work the fact that almost everyone does it.

User avatar
Quietust
Posts: 1492
Joined: Sun Sep 19, 2004 10:59 pm
Contact:

Re: ASM6 - JSR's not doing anything

Post by Quietust » Tue Jan 22, 2019 4:59 am

Pokun wrote:If using OAM-DMA it should be set to 0, which you do correctly though. I suppose Nerdy Nights is "guilty" for this little misconception.
I'm 99% certain that that originated from the "GBAGuy" NES tutorials, not Nerdy Nights.

[edit] Disregard - I was thinking of the mistaken belief that $2003 was a 16-bit register that you had to write twice (like $2005/$2006).
Last edited by Quietust on Tue Jan 22, 2019 4:40 pm, edited 1 time in total.
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.

Pokun
Posts: 1269
Joined: Tue May 28, 2013 5:49 am
Location: Hokkaido, Japan

Re: ASM6 - JSR's not doing anything

Post by Pokun » Tue Jan 22, 2019 7:04 am

Maybe, but it got into Nerdy Nights as well. I learned from Nerdy Nights and also used to get this wrong until I learned more. I thought it was funny that half of the address is set to a PPU port register (starting with $2) and the other to a DMA register (starting with $4).

User avatar
Bregalad
Posts: 7766
Joined: Fri Nov 12, 2004 2:49 pm
Location: Chexbres, VD, Switzerland

Re: ASM6 - JSR's not doing anything

Post by Bregalad » Wed Jan 23, 2019 12:57 am

tokumaru wrote:You can't JSR to a subroutine that clears memory because it also clears the stack ($0100-$01FF), where the return addresses for subroutines are stored. Since you're wiping out the return address, the RTS will try to return to address $0000 (actually $0001, but that's irrelevant), and the program crashes.
Actually back when I started NES programming in 2002 I did a routine that clears memory, exept the stack, and uses TSX instructions to avoid clearing sections pas the stack pointer. I was very proud that this worked. However I must admit this was completely useless since clearing memory is a single-time operation done at startup, so we can put this in the main program and don't need a subroutine in the first place.

Pokun
Posts: 1269
Joined: Tue May 28, 2013 5:49 am
Location: Hokkaido, Japan

Re: ASM6 - JSR's not doing anything

Post by Pokun » Thu Jan 24, 2019 5:24 am

Yeah and if you like the procedural approach of dividing the program into many subroutines, you can make a macro of it instead. It's useful for avoiding the overhead of any subroutine that is only called once, or when speed is more important than space.

Post Reply