Jump to content
IGNORED

Trying to bankswitch ... having troubles


Synthpopalooza

Recommended Posts

A conundrum here ...

 

I am wanting to use a bankswitched ROM for my Sky Scraper game, and stick the title screen code in the very last bank (bank 32).

 

When I do this, and use the gosub titlescreen bank32 and finish the routine with return otherbank ... I try to compile, and get a graphics overrun in bank 0. What am I doing wrong?

 

Attaching code, plus the zip file with the graphics from the current build.

 

 

graphics.zip

ramcharmap6e.bas

ramcharmap6e.bas.a78

ramcharmap6e.bas.bin

Link to comment
Share on other sites

When you change over to bankswitching, all of your code needs to be divided up into 16k banks. You're overrunning your first bank. I went through your code and added the "bank 2", "bank 3" commands and it compiled fine (dividing up the incgraphic statements), but it would still need work as your graphics files would likely need to be re-arranged and maybe re-worked. I only spent a few minutes looking at it, the attached file doesn't fix the problem.


Graphics and code that will be used throughout the game should be placed in the last bank. You can't split character tiles into 2 different graphics blocks - they need to be in one graphics block at any given moment (The area you specified with the "characterset" command). Sprites can go in any of the graphics blocks, can span multiple blocks, and all may be displayed at once.


Sticking 2 graphics blocks into a 16k bank is doable, but you need to use the "dmahole" command before any code in those banks, as the graphics blocks otherwise take up room the code would normally sit in.




A 16k bank with just 1 graphics block...
|<--------------------16k bank------------------>|
| |
|<----------8k----------><-----4k----><---4k---->|
| |
[ BASIC code ][GFX Block 0][DMA Hole 0]

A 16k Bank with 2 graphics blocks...
|<--------------------16k bank------------------>|
| |
|<----4k----><----4k----><-----4k----><---4k---->|
| |
[GFX Block 0][DMA Hole 0][GFX Block 1][DMA Hole 1]



7800 graphic math is a bit tricky. You have 256 bytes of storage in any one graphics block, and your file needs to fit into one block. In 160A mode, 1 byte will display 4 pixels wide, so any one image can be up to 1024 pixels in width... but that's also the maximum that you can store in a graphics block, so if you make one that wide then no other image file can go in that block.


If you have more than 256 bytes of character graphics, you'll have to create separate game loops in separate banks and call the different image files separately with a new characterset command. Mike helped me with that issue when I was working on the adveture/zelda demo a few years back, I should be able to share some sample code if I can dig it up. I don't remember if I shared any code in that adventure demo thread or not.


A few things to note:


-It doesn't matter which block the character graphics are in, but they all need to in the same one.

-Sprite graphics can be spread out in any or all graphics blocks and still be displayed at any time.

-Issuing 'newblock' will force the incgraphic commands that follow it to put graphics into the next block.

-You can change the active graphics block for a characterset with the "characterset imagename" command.


Steve

ramcharmap6e.bas

  • Like 3
Link to comment
Share on other sites

So ideally, What I would like is a separate bank for the title screen along with the graphics for the title screen, and the game code and graphics in the last block. Also, I plan on having 39 levels to the game and I'd like to bankswitch those as well. Is this possible?

 

Sure, it's possible, but it really depends on how many character graphics you need to have active at once. If you can make all 39 levels with the same 256 byte block of graphics data it'll make it a lot simpler. Having never actually completed a bankswitched game with 7800basic I can't really speak from experience, everything I posted earlier is really just a summary of what Mike explained to me a few years back. I am working on figuring out bankswitching right now, actually, as I was just starting to revisit my old adventure demo code in the last few days. That's why I had the info handy to share earlier. :)

Link to comment
Share on other sites

Yep, that should make it a bit easier then. Changing code over to use bankswitching after you've already filled up a 32K or 48K ROM can be a challenge, though, as you may have some contiguous subroutines that are larger than 16K, and that's your limit once you convert. Some code may need to be rewritten to take that into account. You also need to account for waiting for the end of the visible screen before you switch out of a bank (with a drawwait command), or the characters in the bank won't be drawn correctly.

 

I tried unsuccessfully to convert my most recent game to bankswitching (Death Merchant), but I gave up after seeing how difficult it was going to be to convert it based on how I had already written it. I've vowed to now start all future projects with bankswitching already in place. :) I'm just now starting to work on a new bankswitched game. Once I've had some time to work through the changes and limitations in the context of actually writing a game I'll be able to provide much more helpful information than I can right now.

  • Like 1
Link to comment
Share on other sites

So anyway, I tried to re-jig my code as follows ... 528k ROM size, splitting up the graphics between banks 1, 2, and 33, on the assumption that 33 and 1 are always present.

 

When I compile, this shows:

 

(1967): error: Origin reverse-indexed

 

So here's all the files. You can continue to use the graphics from the last upload.

 

I am also thinking of placing important subroutines in the dmaholes. When the program is compiled, does the execution automatically step over the dmaholes, or will I need to place goto's at the beginning so that the code is skipped?

 

 

ramcharmap6h.bas

ramcharmap6h.bas.asm

Link to comment
Share on other sites

So best procedure is to have code destined for a particular bank in a subroutine and use gosub / return otherbank? My idea was to put all the enemy graphics into a bank, and put all the code for enemy movement into a subroutine called moveenemy. So something like this?

 

bank 2

<incgraphic for enemy sprites>

 

moveenemy

 

<code for moving enemy>

 

return otherbank

 

and from the main bank do:

 

gosub moveenemy bank2

 

Would this work?

Link to comment
Share on other sites

That won't work well I don't think. If you end up going to the subroutine during the visible screen, the enemy graphics will get switched out and you'll see garbage displayed. (It'll still try to display whatever sprite happens to be in the same address space as the proper enemy sprites, but it'll be something different there.)

 

You'll probably have to make sure you have the enemy sprites in the same subroutine if they're in the bankswitching range.

 

In Graze Suit Alpha I currently need to make use of 2-3 banks to handle all the stuff for the game. (AI, collision, movement, effects, etc all add up, especially with my less than super efficient coding habits). To make sure the enemy graphics are available at any given time all of the banks that are used have identical graphics banks.

Link to comment
Share on other sites

The problem with the "how should I bankswitch?" question is it often differs from program to program, so there's no satisfactorily concrete reply.

 

Creating a game for any 8-bit system is an exercise in balancing your wanted features against system constraints. Bank-switching trades one constraint (shortage of ROM) for another (ephemeral and segmented ROM). Just as nobody can give one piece of advice that applies to RAM constraints for all games, the same applies for bank switching.

 

Here are some guidelines...

  • Stick whatever graphics are common to game levels/areas in permanent banks.
  • Stick whatever code is common to levels/areas in permanent banks.
  • Only include graphics in any non-permanent bank if you intend to stay in that bank from drawscreen to drawscreen. The exception is that you can bank away after the frame is drawn, and return before the next frame is drawn, but this is tricky to pull-off in practice; if you take too long away from the bank, you'll mess up the display.
  • Maria doesn't implement dma holes in ROM from 4000-7FFF, so if you stick sprite graphics here *and* code, it will cause glitching when the sprites move vertically. The reason sprite data works here at all is because I instruct DASM to fill unused space with "0" bytes. So in summary, for ROM@4k use either all code, or code+characters, or sprites+characters, but don't use code+sprites.
  • As Mord alluded: To make your game design work, you may need to duplicate code in some banks. Or you may need to duplicate graphics in some banks. This wastefulness is normal.
With that in mind you have the info to take a best shot for your design. You may implement and discover halfway that you'd like certain features that will force a different bank-switch design, or some exceptions to your current design. This is unfortunately normal. The same will be true if you run up against other constraints, like RAM.
  • Like 4
  • Thanks 1
Link to comment
Share on other sites

But what If your graphics are split between two banks, one of them being the last bank which is always prrsent? Does that make a difference?

I like to have the graphics in the last bank but at times you may need to insert graphics into, say, the first bank for title graphics. Keep in mind storing graphics and code into another bank will eat up a lot of memory for that bank. I like to call the last bank the "vault" since graphics and only graphics go into that bank. I'm guessing each bank is still 16K in size? So, for instance a 128K game will have eight banks (16 x 8= 128). You could have graphics and code in the first bank for titles and title screen code. Then banks 2-7 you'll just have game code. Finally, bank 8 will have the rest of graphics.

 

With a 48K game, could you call up 3 banks, each 16K? I always thought it was already done for you.

  • Like 1
Link to comment
Share on other sites

OK, so here's the situation:

 

I am trying to compile the game into a 528K ROM, which (if I understand correctly) allows the first and last banks (1 and 33) to be present all the time.

 

My plan is, titlescreen in the last bank (along with graphics), graphics in the first bank, main game code in bank 2 along with any extra graphics that won't fit into bank 1. So I did some reshuffling, trying to get everything to fit into these three banks, and I am having troubles. I am attaching the code ... can you suggest anyway I can reorganize this so that everything fits?

 

 

ramcharmap7.bas

Link to comment
Share on other sites

  • 2 years later...

I am out of room on Popeye. I came to this thread, but I am really unclear on how to separate my game into banks.

 

I tried separating the graphics, just to find balance. I am always over on the last.

 

I chose 128k. I was advised that the RAM could help with music, so I chose 128kBANKRAM.

 

Do I define all of my variables in the last bank?

Where do I place my sound effect Data?

Most of my graphics are on-screen at the same time. Should I place Brutus's graphics withing a "Plot Brutus" routine?

 

Likewise, should Popeye's graphics and all of his plot routines fit into one bank?

 

Brutus is nicely separated, with his own "PlotBrutus" routine. Popeye is still kind of mixed within the main Walk routine, as his logic isn't as separated out.

 

There's a start. Sorry for the vague original post. I got a phone call and accidentally sent.

 

-- Darryl

Edited by darryl1970
Link to comment
Share on other sites

The variables can be defined anywhere in your code, in any bank. dim statements don't actually use up rom, or get located in any particular place, they just tell 7800basic "I'm going to refer to this bit of memory with the following name, from now on."

 

There isn't a set place for sound effects, graphics, etc.. The principal to keep in mind, is that every bank except the last bank, disappears when you switch to another bank. So when you're executing code in bank 1, the rom layout looks like this...

/---------------\
|   BANK   1    |  ROM 8000-BFFF
\---------------/

/---------------\
|   BANK   8    |  ROM C000-FFFF
\---------------/

...and then if you "goto myroutine bank2", bank 1 goes away and the rom layout now looks like this...

/---------------\
|   BANK   2    |  ROM 8000-BFFF
\---------------/

/---------------\
|   BANK   8    |  ROM C000-FFFF
\---------------/

...so while you're in bank 2, you can't correctly access anything from any other bank, except bank 2 and 8.

 

If you call "drawscreen" from bank 1, and then decide you need to "goto myroutine bank2", you hide any graphics you've placed in bank 1 away from Maria, and you'll get blobs on the screen.

 

The rule of thumb is to stick all of the common graphics you can in bank 8. Once you've done that, the next natural thing for your game is to stick any level-specific graphics in a level-specific bank. In these level specific banks, you'll need a copy of the main loop and any routines the main loop uses, so you don't need to go to another bank while the screen is being displayed. (or else you'll get Maria displaying blobs) If you don't have enough room in the last bank for all common graphics, then stick a slightly-different named copy of those common graphics in every single bank that you have a main loop in.

 

As far as where your plot* routines happen... Normally the advice is to place all game logic after drawscreen, followed by all of the plot* routines with as little display logic as possible. But since you're using framebuffering, it doesn't really matter where you stick the plot routines, or how intermixed they are with the game logic. So that's entirely up to you.

  • Like 1
Link to comment
Share on other sites

That's one approach, and one that will probably work well for a game that has a bunch of graphical change between levels, like Popeye.

 

I just don't want people to get hung up on "levels" being the thing you use to break a game into banks. There are no hard and fast rules here. Someone might have a game design where the levels change as you progress, and different parts of each level require different banks. Or you might have a game like SotA, where it doesn't even have levels as such, and you need to break the banks up by "area type". Yet another game design may be able to fit all of the game loop graphics into the last bank, and just use bankswitching for game data, logic, and title screen graphics.

  • Like 1
Link to comment
Share on other sites

I guess I am hung up on the need for Popeye, Brutus, Sea Hag, bottles, and background graphics all to be displayed at the same time. I have a LOT of graphics frames, and they do not all fit into one bank.

 

I worked hard to limit my levels to 3 tile sets each. That eats up a lot of space in itself.

 

So, I can't goto PlotPopeye bank2, return to MainLoop bank8, PlotBrutus bank3, return to MainLoop?

 

It sounds as if I'll loose Popeye.

 

I tried to store my graphics in 8, along with Main. I feel like I am just blowing up my program and getting nowhere.

 

To be clear....

 

Is it goto/gosub PlotPopeye "bank2" or "bank 2"?

 

I saw a sample code that said "returnbank" is that a thing? How do I get back to the bank that called bank 2?

 

I might need to put Popeye up and write smaller programs to get the hang of this first.

 

--Darryl

Link to comment
Share on other sites

 

6 hours ago, darryl1970 said:

So, I can't goto PlotPopeye bank2, return to MainLoop bank8, PlotBrutus bank3, return to MainLoop?

Correct. Unless you've placed a copy of the popeye and brutus sprites in banks 2 and 3 (and whichever bank the mainloop runs in), at the same relative locations.

 

The alternative is you could use a 144k format, which puts another permanent bank at $4000. But even then it's highly likely you'll wind up needing to duplicate graphics and/or code in different banks. It's just the nature of the beast, on the 7800, or any other platform with bank switching.

 

Also you should be aware that either using RAM@4000 as you have, or picking a 144k format with ROM@4000, will mean you can't support POKEY@4000. This isn't the biggest deal, since CC2 users can now use POKEY@450 instead of POKEY@4000, but something you should be aware of.

 

6 hours ago, darryl1970 said:

Is it goto/gosub PlotPopeye "bank2" or "bank 2"?

 

I saw a sample code that said "returnbank" is that a thing? How do I get back to the bank that called bank 2?

 

I might need to put Popeye up and write smaller programs to get the hang of this first.

It's "goto bank2". The space separated name is a keyword on it's own, so the condensed version of the bank name is used with goto/gosub to keep it unique. It could have been worked around, but it's also historic bB syntax, and maintaining bB syntax where possible is a design goal of the language, so I left it as-is.

 

You can just "return" from a bankswitched goto/gosub if you like. It's optional, but if you only goto/gosub locally you can also use "return thisbank", or if you only goto/gosub with a bankswitch you can use "return otherbank". The benefit to that is it generates generates small and faster code. The manual covers this also.

 

It's not a bad idea to get some smaller programs under your belt. Learning about bank-switching at the same time you're learning the 7800 and 7800basic is often a bit hairy. You need to be precise in your understanding and implementation of the rom layout, or else the bank switching will just introduce complexity, while much of the extra rom will be squandered.

  • Like 1
Link to comment
Share on other sites

Here are some vb samples.

 

PopeyeBank.bas builds, and it will display both screens. The issue is that the "PopeyeLife" sprite will not display when flipping to Level2. I have the graphic included in both banks, so I am confused.

 

The PopeyeBank(Try...) is broken. I tried to place the shared "NumLetPng.png" and "PopeyeLife" png's in the 8th bank. (I tired bank 9 with 144k and bank 8 with 128k).  I figured I would be good adding the incgraphic to each bank I needed it in. I also thought placing the graphics in bank 8 would be visible from all banks.

 

I thought it might help to call the code first. I figured order may play a difference. It makes no difference.

 

I get this error:

*** (224): ERROR, plotmapfile didn't find a palette for NumLetpng

 

Around line 153, I attempted a gosub InitializeGraphics.

 

PopeyeBank.bas

PopeyeBank(TryToEnableNUMLETPNG_Palett).bas

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