Jump to content
IGNORED

RTS jumps to unintended location


Recommended Posts

Solution:I'm an idiot and forgot to clear the stack. Here's my new start where I clear the stack, if anyone else needs it.

; Modified start of the original program.
START: 		; The start of the program.
		ldx #$FF	; "Clear" X. This gets set to 0 later, right now this is the end point of the RAM and register clearing.
		lda #0		; Clear accumulator. Gets cleared again later.
CLEAR1:		; Clear all RAM, EXCEPT X-bytes from last!
		sta 0, x	; Store accumulator at 0-page, at RAM address X.
		dex			; Decrement X.
		bne CLEAR1	; If X is not 0, loop to CLEAR1.
		ldx #$FF	; Setup for stack clear.
CLEAR2:				; Clear the stack.
		dex			; Decrement X.
		txs			; Put X to the current stack pointer? That's weird. I don't understand why you'd do that.
        ; Commenting out above seemed to work, but I wouldn't recommend it just in case. macro.h uses things I'm not apparently not aware about.
		pha			; Push accumulator to stack, incrementing the stackpointer presumably.
		bne CLEAR2	; If we're not done clearing the stack, loop back to CLEAR2.

Original post:

Hi all! I hate to ask, but I'm currently facing a pretty big problem. I have a 2K rom that looks like this in assembly.

.include "atari.i"	; Atari register positions ported to WLA-DX.
; ROM info setup.
; This is for a 2K non-banked rom.

.ROMBANKMAP
BANKSTOTAL 1
BANKSIZE $0800
BANKS 1
.ENDRO

.MEMORYMAP
DEFAULTSLOT 0
SLOTSIZE $0800
SLOT 0 $f000
.ENDME

.BANK 0 SLOT 0
START: 		; The start of the program.
		ldx #$FF	; "Clear" X. This gets set to 0 later, right now this is the end point of the RAM and register clearing.
		lda #0		; Clear accumulator. Gets cleared again later.
CLEAR:		; Clear all RAM, EXCEPT the last byte!
		sta 0, x	; Store accumulator at 0-page, at RAM address X.
		dex			; Decrement X.
		bne CLEAR	; If X is not 0, loop to CLEAR.
		
SETUP:		; Final preparations.
		ldx #0
		ldy #0
		lda #0
		
LOOP1:	; The first loop.
			; Do some random things.
			adc #10
			adc $EF
			jsr LOOP2 ; Just jump to the draw logic when everything else is done.
CONT:		sta $8e
			lda #33
			adc #64
			adc #$01
			adc inpt5
			sta $84
			ldx inpt4
			stx $EF
			jmp LOOP1 ; And the loop begins anew

LOOP2:
			adc #30
			adc $84
			rts		; Okay, this loop's done! Return!

; Set the interrupts. Don't forget to do this! Final address-6!
.ORGA $F7FA
.dw START		; NMI
.dw START		; RESET
.dw START		; IRQ

The ROM loads up fine, but when I JSR to LOOP2, things get interesting. This is because RTS does NOT return to where CONT: is(compiled to $F016,) but rather an address in the $2XXX range. It's not consistent exactly where it's jumping, it's just somewhere in the $2XXX range.

My only guess is that it's a problem with the stack being given junk data shortly after the JSR, but none of these commands should be transferring to the stack. Does anyone have an idea of what's going sideways here?

I've attached a copy of the compiled ROM for examination, incase you don't want to fiddle with WLA-DX.

rom.a26

Edited by xX_pokeman2003_Xx
Link to comment
Share on other sites

Okay, I just realized my folly. I haven't been trying to clear the stack. In my defense, a program which looked like below worked just fine.

LOOP1:	; The first loop.
			; Doing NOTHING actually works when compiled.
			jsr LOOP2 ; Just jump to the logic when everything else is done.
			jmp LOOP1 ; And the loop begins anew

LOOP2:
			rts		; Okay, this loop's done! Return!

I wish that Stella had some way to view the stack.

Link to comment
Share on other sites

7 minutes ago, xX_pokeman2003_Xx said:

I wish that Stella had some way to view the stack.

Press the tilde (~) key to launch the debug view.

On the right you see a grid of numbers, showing all of zero page.  The stack is of course normally shared with ZP RAM ($80-$FF)

Given, as I said, you did not initialise the stack pointer... your return address may be in that area... or it may be in the $0-$7F range (in other words. lost and not the value you expect).

 

Link to comment
Share on other sites

Firstly, thanks for the quick response. A little too late, I did end up looking at macro.h just to see what it did and noticed the stack clear. I had tried other methods in the past to no avail, so I figured that it just was always initialized, until I saw the stack clearing loop.

2 minutes ago, Andrew Davie said:

You have not initialised the stack pointer, so the stack is probably pointing into TIA registers.

Init your stack pointer with #$FF with a ldx #$FF/txs...

Do you happen to have some good material that I can read into about how the 6502 handles the stack? I'm a complete beginner at assembly, and barely understand any of it. I've found sources in the past, but they all assumed I was already experienced at other assembly languages, or told me things like "the stack is hardcoded to memory values of $0100-$01FF," which is obviously not the case.

Link to comment
Share on other sites

Just now, xX_pokeman2003_Xx said:

Firstly, thanks for the quick response. A little too late, I did end up looking at macro.h just to see what it did and noticed the stack clear. I had tried other methods in the past to no avail, so I figured that it just was always initialized, until I saw the stack clearing loop.

Do you happen to have some good material that I can read into about how the 6502 handles the stack? I'm a complete beginner at assembly, and barely understand any of it. I've found sources in the past, but they all assumed I was already experienced at other assembly languages, or told me things like "the stack is hardcoded to memory values of $0100-$01FF," which is obviously not the case.

You seem to be a little confused here.  You do not clear the stack.  You clear the stack pointer.

The stack pointer, one of the 6502 registers, is an 8-bit value that points to the current top of the stack.  When you push values to the stack, the pointer is decremented. When you pop, it is incremented.  So a JSR pushes two bytes to the stack (the return address), and the stack "grows down" by two bytes. The stack and RAM share memory, $80 - $FF.  So typically you initialise the stack pointer to $FF to point to the top of RAM and stack usage grows down from $FF. And you put your variables at $80 and up, and hope that the two (stack, variables) never collide/overlap.
So, you can clear the stack or not, it makes zero difference. What you do need to do is initialise the pointer -- with. ldx #$FF/txs.

In the '2600, the stack is hardcoded to address $0-$FF (that is, page 0).  It just so happens that locations $0-$7F are not RAM, so you never want your stack pointer to be pointing into that range. If you haven't initialised it at startup... well there's a good chance it just so happens to point there. and... disaster.

Link to comment
Share on other sites

10 minutes ago, Andrew Davie said:

You seem to be a little confused here.  You do not clear the stack.  You clear the stack pointer.

Gee, what gave away the fact I have literally no clue what I'm doing here? Oh, okay, that makes more sense. That explains the CLEAN_START macro's usage of TXS. That also explains how the RAM is cleared too on the macro, though I don't understand how the stack pointer remains at $FF if you're pushing a decrementing X register to it and then never put $FF in it again.

10 minutes ago, Andrew Davie said:

The stack pointer, one of the 6502 registers, is an 8-bit value that points to the current top of the stack.  When you push values to the stack, the pointer is decremented. When you pop, it is incremented.  So a JSR pushes two bytes to the stack (the return address), and the stack "grows down" by two bytes. The stack and RAM share memory, $80 - $FF.  So typically you initialise the stack pointer to $FF to point to the top of RAM and stack usage grows down from $FF. And you put your variables at $80 and up, and hope that the two (stack, variables) never collide/overlap.
So, you can clear the stack or not, it makes zero difference. What you do need to do is initialise the pointer -- with. ldx #$FF/txs.

In the '2600, the stack is hardcoded to address $0-$FF (that is, page 0).  It just so happens that locations $0-$7F are not RAM, so you never want your stack pointer to be pointing into that range. If you haven't initialised it at startup... well there's a good chance it just so happens to point there. and... disaster.

This is incredibly useful information! Thank you so much!

Edited by xX_pokeman2003_Xx
E1:Fixed a problem with rich text interfering with formatting. Also, added " and then never put $FF in it again." E2:Reformatted unsatisfactory sentences in first paragraph.
Link to comment
Share on other sites

Just now, xX_pokeman2003_Xx said:

Gee, what gave away the fact I have literally no clue what I'm doing here? Oh, okay, that makes more sense. And that's why doing TXS is. That explains how the RAM is cleared too on the CLEAN_START macro, though I don't understand how the stack pointer remains at $FF if you're pushing a decrementing X register to it.

This is incredibly useful information! Thank you so much!

CLEAN_START is using incredibly arcane 6502 knowledge/trickery and should NOT be studied for an understanding of how things are done.

Suffice it to say, through weird trickery it ends up with the stack pointer at $FF.  Just treat it as a black box, if you use the macro.

Otherwise, do what I said. Your clear is OK, but remember it's clearing RAM AND 0-$7F, which is in effect a TIA register clear.

You are effectively clearing $80-$FF which is all of RAM - and hence you are also clearing the stack area which is $FF downwards...but that's only if you also point the stack pointer to that area (i.e., init with #$FF -- the standard that most programs use).

Link to comment
Share on other sites

12 minutes ago, xX_pokeman2003_Xx said:

"the stack is hardcoded to memory values of $0100-$01FF," which is obviously not the case.

That's actually correct: in every 6502 based system, including the 2600, the stack is in page 1.

It just happens that in the 2600 page 1 is a mirror of page 0, so it's easier to consider the stack being in page 0 too, as it uses the same physical memory as the zero page ram.

  • Like 1
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...