Jump to content
Mallard Games

Somehow I end up in RAM

Recommended Posts

Hi again,

 

Did a bit of restructuring and now it seems to go to the correct bank on power up. The issue I think is right after that it jumps into no man's land a.k.a RAM and never returns which results in a black screen with a brown messed up playfield and a horrible death sound. 😝 The strange part is bank 0 is so small it is latterly only a few bytes in size with only a few calls to the required syncing subroutine, and then the title screen kernel  which draws the title screen using the playfield and yes all the graphics are in the same bank.

 

Links

Source

Listing

Binary

Share this post


Link to post
Share on other sites

You appear to be starting up in Bank 0, and calling VerticalSync (which is in another bank) without actually switching that bank in.

I don't know enough about the bankswitch scheme you are using to know if that's an issue, but stella certainly doesn't seem to be stepping into that routine. So I'd be looking at which banks are switched in, and where the subroutines you call actually live.

 

Share this post


Link to post
Share on other sites
17 minutes ago, Andrew Davie said:

If you step through it with Stella's debugger, you should be able to spot the problem. Worth learning.

 

 

Alright I'll pretent I'm the world famous Andrew Davie who's disassembling yet another game. 🧐

 

Ok, this is strange to me:

L101f	.byte a0 ;ldy	;2-6

That is this bit of code:

	sta	Random	; use it to seed the random number generator

Next line:

L1020	jsr L101F	;6

That should be this this:

	jsr	VerticalSync	; perform vertical sync

but instead it's jumping back to our sta Random code, very weird. Anyways:

1029	jmp L1020	;3

This should be jumping to the top of our loop, but instead it's jumping back to our vertical sync routine..... and then to top it all off it jumps back to

	sta Random

instead of the top of the title screen loop.

 

Update: All my subroutines and "logic" live in Bank 2. Bank 3 is reserved for sound effects and music. So I have to add a

	sta $FFF8				; bank into subroutines

every time I want to call a subroutine? That can amount to dozens of repetitions of the above code.

Edited by Mallard Games

Share this post


Link to post
Share on other sites

Sometimes the debugger gets confused about which label to use when more than one have the same value, and also what is code and what is not code. But that area is exactly a clue that something is going wrong right there. It just so (unfortunately for you) happens that the label 'verticalsync' happens to correspond to that particular position in your code in BANK 0.

If you step through (let's ignore the first time), then at the bottom of the loop it jumps to "TitleScreenLoop"

Then the first thing it does is "jsr VerticalSync".  Note that that label is displayed by the debugger as being one BYTE up above that call

So it jsr's to the '$a0' as code, and tries to execute that. Uh oh. It should be jsr'ing to the VerticalSync at that address IN THE OTHER BANK, not this one. That's your problem, almost certainly. As I said, incorrect bank switched in for call to that subroutine.

 

Share this post


Link to post
Share on other sites

Oh, and kudos for making the effort and actually looking at the debugger. It is a very handy tool which will be your best friend before you know it.

 

Share this post


Link to post
Share on other sites

I am not familar with the ins and outs of the bankswitch scheme you are using, so I'm no help sorry.

But basically, if you have stuff in different banks, then you have to make sure your desired bank is accessible before using it!

And, in some schemes you have to be careful about switching OUT the bank you're in when you try to switch in another bank you need.

So, that's all I'll say - work on your bankswitching :)

 

Share this post


Link to post
Share on other sites
14 minutes ago, Andrew Davie said:

I am not familar with the ins and outs of the bankswitch scheme you are using, so I'm no help sorry.

But basically, if you have stuff in different banks, then you have to make sure your desired bank is accessible before using it!

And, in some schemes you have to be careful about switching OUT the bank you're in when you try to switch in another bank you need.

So, that's all I'll say - work on your bankswitching :)

 

I'm using the standard Atari F6 bankswitching scheme.

Share this post


Link to post
Share on other sites
1 minute ago, Mallard Games said:

I'm using the standard Atari F6 bankswitching scheme.

First I've heard of it :)

 

Share this post


Link to post
Share on other sites
F6: 'hot spots' are 1FF6, 1FF7, 1FF8, and 1FF9.  By accessing these addresses,
you can select which 4K block to use.  Note that accessing one of these
addresses changes the *whole* 4K block!  You must make sure you pick up
where you left off in your code!  i.e. If you're executing a program 
fragment in bank 0 (1FF6) and want to change to bank 1 (1FF7), you do
so by issuing a 'fake' read of some sort.  ususally it's by an 'LDA $xxxx'-
type instruction.  When the LDA $1FF7 (in our case) finishes executing,
the processor will be in the #1 bank, with the program counter otherwise
un-affected.  So, to execute a subroutine in bank 2 from bank 1 we have to:

Bank #1                               Bank #2
--------------------------------------------------------------
1000 JSR $1800 (do subroutine)        .
1003 (program continues)              1200 _subroutine goes here_
.                                     1209 RTS
.                                     .
1800 LDA $1FF8 (switch to bank 2)     1802 (rest of program)
1803 NOP                              1803 JSR $1200
1804 NOP                              .       
1805 NOP                              .       
1806 NOP                              1806 LDA $1FF7  (Switch back to bank 1)        
1807 NOP                              .
1808 NOP                              .
1809 RTS   (We're done w/ routine)    1809 (rest of program)                          

OK, we start out in bank #1 and we want to run a subroutine in bank #2.

What happens is this- the processor starts at 1000h in bank #1.  We call
our subroutine from here.  1800h:  We do a read to change us to bank #2.
Remember that when we change banks, we are basically doing a ROM swap.
(You can think of bankswitching as 'hot-swapping' ROMs)  Now that we're
in bank #2, the processor sees that JSR to $1200, which is the subroutine
that we wanted to execute.  We execute the subroutine and exit it with an
RTS.  This brings us back to 1806h.  We then do another read to select bank
#1.  After this instruction finishes, the processor is now in bank #1, with
the program counter pointing to 1809, which is an RTS which will take us
back to 1003 and let us continue on with our program.




Ugly!

Share this post


Link to post
Share on other sites
5 hours ago, Andrew Davie said:
F6: 'hot spots' are 1FF6, 1FF7, 1FF8, and 1FF9.  By accessing these addresses,
you can select which 4K block to use.  Note that accessing one of these
addresses changes the *whole* 4K block!  You must make sure you pick up
where you left off in your code!  i.e. If you're executing a program 
fragment in bank 0 (1FF6) and want to change to bank 1 (1FF7), you do
so by issuing a 'fake' read of some sort.  ususally it's by an 'LDA $xxxx'-
type instruction.  When the LDA $1FF7 (in our case) finishes executing,
the processor will be in the #1 bank, with the program counter otherwise
un-affected.  So, to execute a subroutine in bank 2 from bank 1 we have to:

Bank #1                               Bank #2
--------------------------------------------------------------
1000 JSR $1800 (do subroutine)        .
1003 (program continues)              1200 _subroutine goes here_
.                                     1209 RTS
.                                     .
1800 LDA $1FF8 (switch to bank 2)     1802 (rest of program)
1803 NOP                              1803 JSR $1200
1804 NOP                              .       
1805 NOP                              .       
1806 NOP                              1806 LDA $1FF7  (Switch back to bank 1)        
1807 NOP                              .
1808 NOP                              .
1809 RTS   (We're done w/ routine)    1809 (rest of program)                          

OK, we start out in bank #1 and we want to run a subroutine in bank #2.

What happens is this- the processor starts at 1000h in bank #1.  We call
our subroutine from here.  1800h:  We do a read to change us to bank #2.
Remember that when we change banks, we are basically doing a ROM swap.
(You can think of bankswitching as 'hot-swapping' ROMs)  Now that we're
in bank #2, the processor sees that JSR to $1200, which is the subroutine
that we wanted to execute.  We execute the subroutine and exit it with an
RTS.  This brings us back to 1806h.  We then do another read to select bank
#1.  After this instruction finishes, the processor is now in bank #1, with
the program counter pointing to 1809, which is an RTS which will take us
back to 1003 and let us continue on with our program.




Ugly!

Well I've made some progress at least. The issue I'm having now is trying to figure out how the #^*_ I'm supposed to get back to the correct respective display bank. I figured out how to get to the subroutine bank to perform the subroutines but, now how to get back! 🙈🙉🙊

 

Source

Share this post


Link to post
Share on other sites
22 minutes ago, Mallard Games said:

Well I've made some progress at least. The issue I'm having now is trying to figure out how the #^*_ I'm supposed to get back to the correct respective display bank. I figured out how to get to the subroutine bank to perform the subroutines but, now how to get back! 🙈🙉🙊

 

Source

As the documentation posted gives an example, I suggest you read it carefully. You need to bankswitch again, back to the original. But you have to have the correct code at the very next PC address after the bankswitch.  That is, if you are in bank 2, and you want to return to bank 0, then just after the bankswitch read/write to bank 0, execution will *continue* from the current PC address... but in bank 0.  You need to know exactly where you're "at", so to speak, and write the code accordingly. That's why I said "ugly!". It must be a nightmare to program using this scheme.

Edited by Andrew Davie
removed dumb suggestion

Share this post


Link to post
Share on other sites
15 minutes ago, Andrew Davie said:

As the documentation posted gives an example, I suggest you read it carefully. You need to bankswitch again, back to the original. But you have to have the correct code at the very next PC address after the bankswitch.  That is, if you are in bank 2, and you want to return to bank 0, then just after the bankswitch read/write to bank 0, execution will *continue* from the current PC address... but in bank 0.  You need to know exactly where you're "at", so to speak, and write the code accordingly. That's why I said "ugly!". It must be a nightmare to program using this scheme.

The only other option is to waste space by duplicating the subroutines every bank which defeats the purpose of having the extra space in the first place. @Andrew Davie weren't you a programmer back in the day?

 

@Nukey Shay We're a bit stumped on how to proceed and need your godly advice.

Share this post


Link to post
Share on other sites
3 hours ago, Mallard Games said:

The only other option is to waste space by duplicating the subroutines every bank which defeats the purpose of having the extra space in the first place. @Andrew Davie weren't you a programmer back in the day?

Yes, I was. I would never use a bankswitching scheme like this one, given a choice :) . 

I don't think you are correct that "the only other option is..", but I do think that you're going to have a lot of pain ensuring that your code works.

 

Share this post


Link to post
Share on other sites
34 minutes ago, Andrew Davie said:

Yes, I was. I would never use a bankswitching scheme like this one, given a choice :) . 

I don't think you are correct that "the only other option is..", but I do think that you're going to have a lot of pain ensuring that your code works.

 

Ok assuming I was you, what bankswitching scheme would I use? 😇

Share this post


Link to post
Share on other sites

Once you have macros/routines setup to abstract the process, you really don't have to think about the underlying bankswitching scheme much, and can switch to a different one under the hood if you need to with a minimum of pain.

Share this post


Link to post
Share on other sites
34 minutes ago, Mallard Games said:

Ok assuming I was you, what bankswitching scheme would I use? 😇

Assuming you were me, you'd most likely design your own bankswitching scheme because you'd be too lazy to learn how to use the ones that are out there ;) but to be serious for just a few seconds... the bankswitching scheme you use depends on the needs of the game you want to write. There are pros and cons for each, and you need to understand those. For example, my games these days (what few there are) like having lots of RAM to play with. So I choose a bankswitch scheme that allows that.

Share this post


Link to post
Share on other sites
14 hours ago, Andrew Davie said:

It must be a nightmare to program using this scheme.

Not at all.  Since F8 is the most-common scheme out there, and F6 & F4 are just adding additional 4k blocks, those are virtually identical.  Just the hotspots need adjusting between all 3 schemes.  And an additional 128 bytes of SARA Ram can later be added just by leaving the first 256 bytes of Rom untouched.

 

The OP needs to get accustomed to how bankswitching is accomplished...this is the ~Nth example of this specific programs' routines being called when a different bank is switched in.  I'd suggest scaling things back to 8k (F8) until those introductory issues are learned to be avoided.  Once F8 is skillfully managed, then move to larger Rom sizes.

Share this post


Link to post
Share on other sites
14 minutes ago, Nukey Shay said:

Not at all.  Since F8 is the most-common scheme out there, and F6 & F4 are just adding additional 4k blocks, those are virtually identical.  Just the hotspots need adjusting between all 3 schemes.  And an additional 128 bytes of SARA Ram can later be added just by leaving the first 256 bytes of Rom untouched.

 

The OP needs to get accustomed to how bankswitching is accomplished...this is the ~Nth example of this specific programs' routines being called when a different bank is switched in.  I'd suggest scaling things back to 8k (F8) until those introductory issues are learned to be avoided.  Once F8 is skillfully managed, then move to larger Rom sizes.

The issue with that is I don't remember if I had enough space for my title screen since most of the space was taken by the playfield data that the title screen is made up of.

Edited by Mallard Games

Share this post


Link to post
Share on other sites

Solution:

Don't use a title screen for now.  Get the game working first.  Eye candy can (and should) be added later.

Share this post


Link to post
Share on other sites

Hey,

 

Sorry for the silence, but I tried using the Medevil Mayhem macros to get bankswitching to work sith no success. What's weird is Stella detects it as a non-bankswitched game and not a F6 bankswitched one. Anyways I am post the latest code here to see if anyone can figure out what's going on.

 

Source

Bankswitch Macro

List File

Binrary

Share this post


Link to post
Share on other sites

That is because A) your vectors are in the wrong locations again, and B) your program has untagged code following JMP instructions.

 

A) for whatever reason, you commented out the NMI vector.  Even tho the macro then declares RORG to be $FFFC for the next 2 vectors, Dasm is still using $FFFA as the actual Rom address.

Keep in mind that only ORG has the ability to reset the address.  RORG just forces the addresses to be called something else.

Solution: reinstate the NMI vector (or add 2 bytes of filler) to make up for the 2-byte shortfall.  The following RORG $FFFC is not needed at all.

 

B) You've got JMP's and JSR's intermingled everywhere, so it's difficult to follow which is supposed to be which.  Consider the following loop:

GameLoop
    jmp VerticalSync                        ; perform vertical sync
    jmp CheckJoystick                        ; check for joystick input
    jmp ClampObjects                        ; clamp the objects to the screen
    jmp PositionObjects                        ; position the objects
    jsr GameScreen_Kernal                    ; jump to game kernal
    jmp OverScan                            ; (3 13) jump to OverScan Routine
    jmp GameLoop

 

The program jumps to VerticalSync and no tags exist below it, so the rest of the loop is never executed at all.  Are these supposed to be subroutines or jumps?

 

 

Take my advice.  Go back to F8.  Babystep until you've got something that runs.

Share this post


Link to post
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.

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...