Can't figure out why my subroutines aren't working

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.
rosly
Posts: 7
Joined: Mon May 26, 2025 5:33 pm

Can't figure out why my subroutines aren't working

Post by rosly »

I'm trying to "learn from scratch" how to program a NES game with assembly, and I've hit my first hurdle:

Code: Select all

		include "nesdefs.dasm"


	NES_HEADER 0,2,1,0 ; mapper 0, 2 PRGs, 1 CHR, horiz. mirror

;;;;; START OF CODE

Start:
; wait for PPU warmup; clear CPU RAM
	NES_INIT
     	ldx #8
        jmp s1

.endless
	jmp .endless	; endless loop
        
s1:
dex
rts 
This minimal example doesn't work (As in, the 8bitworkshop's emulated NES just refuses do do anything and the disassembly just looks like this the whole way through)

Code: Select all

0BE5	FFFFFF        	ISB $FFFF,x                   
0BE8	FFFFFF        	ISB $FFFF,x                   
0BEB FFFFFF        	ISB $FFFF,x                   
0BEE FFFFFF        	ISB $FFFF,x                   
0BF1	FFFFFF        	ISB $FFFF,x                   
0BF4	FFFFFF        	ISB $FFFF,x                   
0BF7	FFFFFF        	ISB $FFFF,x                   
0BFA	FFFFFF        	ISB $FFFF,x                   
0BFD FFFFFF        	ISB $FFFF,x                   
0C00 FFFFFF        	ISB $FFFF,x                   
0C03 FFFFFF        	ISB $FFFF,x                   
0C06 FFFFFF        	ISB $FFFF,x   

and I've tried fiddling with it in various ways, but no luck. I started with 8bitworkshop's minimal initialization example and got rid of as much of it as possible, but given that the included subroutine .endless does work, I'm not sure what I'm doing wrong.

the only code from nesdefs.dasm that's actually run when I use the code with the jmp instruction commented out is the following. I have some more code still in there I haven't deleted, but I don't think it's relevant.

Code: Select all

      
        MAC NES_INIT
        sei			;disable IRQs
        cld			;decimal mode not supported
        ldx #$ff

txs			;set up stack pointer
        inx			;increment X to 0
        stx PPU_MASK		;disable rendering
        stx DMC_FREQ		;disable DMC interrupts
        stx PPU_CTRL		;disable NMI interrupts
	bit PPU_STATUS		;clear VBL flag
        bit APU_CHAN_CTRL	;ack DMC IRQ bit 7
	lda #$40
	sta APU_FRAME		;disable APU Frame IRQ
	lda #$0F
	sta APU_CHAN_CTRL	;disable DMC, enable/init other channels.        
        ENDM
Advice for where I could find more info to help myself a bit would be appreciated, I have struggled to find stuff using web searches.

Sorry my code examples don't have syntax highlighting, haven't learned how to do that yet. Thanks in advance!
User avatar
Quietust
Posts: 2033
Joined: Sun Sep 19, 2004 10:59 pm

Re: Can't figure out why my subroutines aren't working

Post by Quietust »

rosly wrote: Mon May 26, 2025 5:44 pm

Code: Select all

		include "nesdefs.dasm"


	NES_HEADER 0,2,1,0 ; mapper 0, 2 PRGs, 1 CHR, horiz. mirror

;;;;; START OF CODE

Start:
; wait for PPU warmup; clear CPU RAM
	NES_INIT
     	ldx #8
        jmp s1

.endless
	jmp .endless	; endless loop
        
s1:
dex
rts 
This minimal example doesn't work (As in, the 8bitworkshop's emulated NES just refuses do do anything and the disassembly just looks like this the whole way through)
The first problem is that you're doing JMP s1 even though s1 has an RTS instruction at the end - if you want to be able to call a subroutine and then return from it, you have to do JSR s1.
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.
rosly
Posts: 7
Joined: Mon May 26, 2025 5:33 pm

Re: Can't figure out why my subroutines aren't working

Post by rosly »

I've updated my code to use JSR, but that hasn't fixed anything. As long as the subroutine is reachable in code (JMP, JSR, BNE, etc.) everything completely breaks.
Oziphantom
Posts: 2001
Joined: Tue Feb 07, 2017 2:03 am

Re: Can't figure out why my subroutines aren't working

Post by Oziphantom »

your problem is that the system never gets to your code, as you have not defined your Vectors so the RESET vector is $FFFF and hence it will jump to FFFF on start, and then keep going through RAM getting FF all the way through to 0c00 etc . So you need to set the Vectors, maybe your assembler has a system for it, or you need to declare them in your code.
rosly
Posts: 7
Joined: Mon May 26, 2025 5:33 pm

Re: Can't figure out why my subroutines aren't working

Post by rosly »

In that case, why does the code work when I don't have my subroutine active? If I comment out the jump or branch instruction that gets me to the subroutine, the program runts the init function with no issues.
User avatar
Quietust
Posts: 2033
Joined: Sun Sep 19, 2004 10:59 pm

Re: Can't figure out why my subroutines aren't working

Post by Quietust »

rosly wrote: Tue May 27, 2025 5:26 am In that case, why does the code work when I don't have my subroutine active? If I comment out the jump or branch instruction that gets me to the subroutine, the program runts the init function with no issues.
Unless that "jump or branch instruction" is JSR, it's guaranteed to break when it hits the RTS and underflows the stack.

It would be useful if you posted the assembled ROM image so we can actually take a look at it and see why it's not working.
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.
User avatar
Ben Boldt
Posts: 1513
Joined: Tue Mar 22, 2016 8:27 pm
Location: Minnesota, USA

Re: Can't figure out why my subroutines aren't working

Post by Ben Boldt »

rosly wrote: Mon May 26, 2025 8:11 pm I've updated my code to use JSR, but that hasn't fixed anything. As long as the subroutine is reachable in code (JMP, JSR, BNE, etc.) everything completely breaks.
That definitely did fix something, but just because you fixed 1 problem doesn’t mean you fixed all problems.

It’s hard when you first start but this brings to light a good point. It’s possible to write a lot of code, then when you go to try it, it just “doesn’t work” and it’s hard to pinpoint why. Even as you become more experienced with this, it is best to start with something that does work, then make small incremental changes, testing it each step. Then when it doesn’t work, there are fewer things that may have gone wrong.
rosly
Posts: 7
Joined: Mon May 26, 2025 5:33 pm

Re: Can't figure out why my subroutines aren't working

Post by rosly »


Unless that "jump or branch instruction" is JSR, it's guaranteed to break when it hits the RTS and underflows the stack.

It would be useful if you posted the assembled ROM image so we can actually take a look at it and see why it's not working.
I've updated my code to use a JSR instead of a JMP, but the error I'm getting has nothing to do with interrupts being ignored, it doesn't get that far when trying to execute.

current code:

Code: Select all

		include "nesdefs.dasm"


	NES_HEADER 0,2,1,0 ; mapper 0, 2 PRGs, 1 CHR, horiz. mirror

;;;;; START OF CODE

Start:
; wait for PPU warmup; clear CPU RAM
	NES_INIT
        

     	ldx #8
     	;jsr s1

.endless
	jmp .endless	; endless loop
        
s1
dex
rts
   
    

;;;;; INTERRUPT HANDLERS

NMIHandler:
	rti

;;;;; CPU VECTORS
	NES_VECTORS
	
and the macros being used:

Code: Select all

 
 
 ;;;;; NES_INIT SETUP MACRO (place at start)
        
        MAC NES_INIT
        sei			;disable IRQs
        cld			;decimal mode not supported
        ldx #$ff

txs			;set up stack pointer
        inx			;increment X to 0
        stx PPU_MASK		;disable rendering
        stx DMC_FREQ		;disable DMC interrupts
        stx PPU_CTRL		;disable NMI interrupts
	bit PPU_STATUS		;clear VBL flag
        bit APU_CHAN_CTRL	;ack DMC IRQ bit 7
	lda #$40
	sta APU_FRAME		;disable APU Frame IRQ
	lda #$0F
	sta APU_CHAN_CTRL	;disable DMC, enable/init other channels.        
        ENDM

;;;;; NES_VECTORS - CPU vectors at end of address space

	MAC NES_VECTORS
	seg Vectors		; segment "Vectors"
	org $fffa		; start at address $fffa
       	.word NMIHandler	; $fffa vblank nmi
	.word Start		; $fffc reset
	.word NMIHandler	; $fffe irq / brk
	ENDM
 
 
Not sure how to get the assembled ROM, but here's a dissassembly of what it looks like with the jsr instruction commented out:

Code: Select all


;;nothing but BRK above
7FFE	00            	BRK                           
7FFF	00            	BRK                           
8000	78            	SEI                           ; Start
8001	D8            	CLD                           
8002	A2FF          	LDX #$FF                      
8004	E8            	INX                           ; txs
8005	8E0120        	STX PPU_MASK                  
8008	8E1040        	STX DMC_FREQ                  
800B	8E0020        	STX PPU_CTRL                  
800E	2C0220        	BIT PPU_STATUS                
8011	2C1540        	BIT APU_STATUS                
8014	A940          	LDA #$40                      
8016	8D1740        	STA JOYPAD2                   
8019	A90F          	LDA #$0F                      
801B	8D1540        	STA APU_STATUS                
801E	A208          	LDX #$08                      
8020	4C2080        	JMP 0.endless                 ; 0.endless
8023	40            	RTI                           ; s1
8024	FFFFFF        	ISB $FFFF,x                   
8027	FFFFFF        	ISB $FFFF,x                   
802A FFFFFF        	ISB $FFFF,x       
;; nothing but FFFFFF below            
and with it included:

Code: Select all

0000	FFFFFF        	ISB $FFFF,x                   ; NES_MIRR_HORIZ
0003	FFFFFF        	ISB $FFFF,x                   ; CTRL_NT_2C00
0006	FF2AF7        	ISB $F72A,x                   
0009	EFDFFF        	ISB $FFDF                     
000C	FFFFFF        	ISB $FFFF,x                   
000F	BFFFFF        	LAX $FFFF,y                   
0012	FFFFFF        	ISB $FFFF,x                   

;; FFFFFF blocks truncated

01FB	FFFFFF        	ISB $FFFF,x                   
01FE	22            	KIL                           
01FF	80FF          	NOP #$FF                      
0201	FFFFFF        	ISB $FFFF,x                   
0204	FFFFFF        	ISB $FFFF,x             

;; more FFFFFF blocks truncated
Last edited by rosly on Tue May 27, 2025 6:53 am, edited 1 time in total.
rosly
Posts: 7
Joined: Mon May 26, 2025 5:33 pm

Re: Can't figure out why my subroutines aren't working

Post by rosly »

That definitely did fix something, but just because you fixed 1 problem doesn’t mean you fixed all problems.

It’s hard when you first start but this brings to light a good point. It’s possible to write a lot of code, then when you go to try it, it just “doesn’t work” and it’s hard to pinpoint why. Even as you become more experienced with this, it is best to start with something that does work, then make small incremental changes, testing it each step. Then when it doesn’t work, there are fewer things that may have gone wrong.
That's what I'm trying to do, but subroutines are pretty fundamental, it's hard to write a useful program without them.

Anyway, the following program works without issue:

Code: Select all



		include "nesdefs.dasm"


	NES_HEADER 0,2,1,0 ; mapper 0, 2 PRGs, 1 CHR, horiz. mirror

;;;;; START OF CODE

Start:
; wait for PPU warmup; clear CPU RAM
	NES_INIT
        

     	ldx #8
        inx
        dex
        lda #8
        adc #200
        sta $9000
        ldx $9000
        
        
     	;jsr s1

.endless
	jmp .endless	; endless loop
        
s1
dex
rts
   
    

;;;;; INTERRUPT HANDLERS

NMIHandler:
	rti

;;;;; CPU VECTORS
	NES_VECTORS
	


Oziphantom
Posts: 2001
Joined: Tue Feb 07, 2017 2:03 am

Re: Can't figure out why my subroutines aren't working

Post by Oziphantom »

that looks fine, so might be something with the ROM file itself. Attach the ROM so we can fire it up in a debugger and see what is going wrong.
User avatar
Ben Boldt
Posts: 1513
Joined: Tue Mar 22, 2016 8:27 pm
Location: Minnesota, USA

Re: Can't figure out why my subroutines aren't working

Post by Ben Boldt »

rosly wrote: Tue May 27, 2025 6:53 am That's what I'm trying to do, but subroutines are pretty fundamental, it's hard to write a useful program without them.
The TMS9900 in the TI-99 did not have a stack and did not support subroutines! I agree that they are fundamental and it would be terrible not to have them, but it IS possible to go without.
rosly
Posts: 7
Joined: Mon May 26, 2025 5:33 pm

Re: Can't figure out why my subroutines aren't working

Post by rosly »

here's the rom! ex0(1) is with the jsr, the other is without.
You do not have the required permissions to view the files attached to this post.
User avatar
Memblers
Posts: 4153
Joined: Mon Sep 20, 2004 6:04 am
Location: Indianapolis

Re: Can't figure out why my subroutines aren't working

Post by Memblers »

Looking at the ROM, I have a guess as to whats happening.

I think this:

s1
dex
rts

is maybe being interpreted as 3 labels, not 1 label and 2 instructions. Try adding a tab or space before the instructions. the ex0(1) ROM doesn't have the DEX and RTS in there, it's JSR'ing to that following RTI instruction.
rosly
Posts: 7
Joined: Mon May 26, 2025 5:33 pm

Re: Can't figure out why my subroutines aren't working

Post by rosly »

That's the bug, thank you

I did not think about relevant whitespace being an issue! And you'd think that asm instructions would be reserved or something but...

Anyway, much appreciated.
User avatar
Ben Boldt
Posts: 1513
Joined: Tue Mar 22, 2016 8:27 pm
Location: Minnesota, USA

Re: Can't figure out why my subroutines aren't working

Post by Ben Boldt »

Yup that's assembly for you. Labels are fully against the left side and then instructions are after the first whitespace. The whitespaces can be any number of spaces or tabs and they don't have to line up or anything, but you do have to have one. Have fun! :mrgreen:

Feel free to come back to us with more questions please.

Edit:
Removed generally incorrect statements.
Last edited by Ben Boldt on Tue May 27, 2025 11:25 am, edited 1 time in total.