xX_pokeman2003_Xx Posted November 17, 2022 Share Posted November 17, 2022 (edited) 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 November 17, 2022 by xX_pokeman2003_Xx Quote Link to comment Share on other sites More sharing options...
+Andrew Davie Posted November 17, 2022 Share Posted November 17, 2022 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, or better yet use the startup macro in macro.h to clear memory and set the stack pointer. 1 Quote Link to comment Share on other sites More sharing options...
xX_pokeman2003_Xx Posted November 17, 2022 Author Share Posted November 17, 2022 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. Quote Link to comment Share on other sites More sharing options...
+Andrew Davie Posted November 17, 2022 Share Posted November 17, 2022 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). Quote Link to comment Share on other sites More sharing options...
xX_pokeman2003_Xx Posted November 17, 2022 Author Share Posted November 17, 2022 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. Quote Link to comment Share on other sites More sharing options...
+Andrew Davie Posted November 17, 2022 Share Posted November 17, 2022 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. Quote Link to comment Share on other sites More sharing options...
xX_pokeman2003_Xx Posted November 17, 2022 Author Share Posted November 17, 2022 (edited) 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 November 17, 2022 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. Quote Link to comment Share on other sites More sharing options...
+Andrew Davie Posted November 17, 2022 Share Posted November 17, 2022 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). Quote Link to comment Share on other sites More sharing options...
xX_pokeman2003_Xx Posted November 17, 2022 Author Share Posted November 17, 2022 Okay, thank you so much! I'm definitely coming away from this with a much better understanding of what I'm doing. The TIA register is intentionally cleared because I like to make sure every variable is accounted for. Have a good day sir! Quote Link to comment Share on other sites More sharing options...
alex_79 Posted November 17, 2022 Share Posted November 17, 2022 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. 1 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.