Jump to content
IGNORED

Bank Switching Template?


fultonbot

Recommended Posts

Does anyone have a template or sample of how to properly use bank switching in 128KRAM game (or 128KBANKRAM).

I'm not looking for anything fancy, just maybe  sample to answer these questions:
 

1. Which bank is always resident? (the last one? is that bank 8 in 128K?) 

2. How many times have a define a bank? If once, do I put all the incgraphic commands inside the bank definition?

3. Is there pattern that puts utility code in single bank to call across banks?

4 Is it common to have to replicate code in multiple banks (or include font multiple times)

 

Thanks in advance to all the great people here.

 

Link to comment
Share on other sites

I don't have a template but I'll try to answer as best I can.

 

1. Yes, with 128kb it's bank 8. With 144k you get both bank 8 and bank 1, but the downside is you can't have 144k with extra RAM.

 

2. You split up your code with the command 'bank #' to flag everything below that line as belonging to the given bank number until it hits either the end of your source code or another bank command. When you use incgraphic, incbanner, or any other method of importing data, they will be imported to whichever bank you last specified.

This is important to consider when it comes to graphics because if you draw graphics that aren't in bank 8, if you change banks the 7800 will draw whatever is at the same spot in the bank you're currently in. This means you may choose to import graphics into multiple banks (in the same order so they're in the same position).

 

3. I'm not sure what you're asking here, but you can call subroutines from any bank by giving the bank it sits in as a parameter. You have to remember though that it swaps banks to run the code and then swaps back so you can't call a subroutine in bank 5 from bank 3, and expect it to have visibility of data in bank 3.

 

4. Yes, this is very common across all games on all consoles that have bank switched cartridges. To give you a couple of examples, in Spire of the Ancients I have no way of knowing which bank it will be in when it needs to start drawing the screen so the first thing in every bank is a (for the most part) identical copy of my 'topscreenroutine'. Another example is that I was going through some code and found a spot where I was repeatedly jumping to another bank to run a routine and found that the small amount of setup needed to change banks in the background was eating a surprisingly hefty bit of ROM so I simply duplicated the routine to avoid switching banks which saved space and improved the speed.

  • Like 2
  • Thanks 1
Link to comment
Share on other sites

For a non-bankswitched game the topscreenroutine can go anywhere.

 

The trick to using it with bankswitching is that you need to realise that a label is just an easy to read representation of a numerical address, and that when you switch banks you're switching the values at those same addresses and not swapping to a different set of addresses. For example, when you compile your game, topscreenroutine might represent address $1234, but what's at $1234 won't be the same in different banks without extra work so you might end up with your code jumping to $1234 expecting to run the topscreenroutine and instead finds itself in the middle of a block of data processing nonsense and ultimately crashing.

To get around that we need to make sure that $1234 contains the right code in whichever banks we need and the easiest way to do that is to put the code immediately after the bank # command so it's in the same spot. You still can't have multiple labels with the same name so only one copy is called topscreenroutine and in my code the others are things like topscreenroutinebank2, topscreenroutinebank3, etc.

  • Thanks 3
Link to comment
Share on other sites

53 minutes ago, SmittyB said:

I don't have a template but I'll try to answer as best I can.

 

1. Yes, with 128kb it's bank 8. With 144k you get both bank 8 and bank 1, but the downside is you can't have 144k with extra RAM.

 

 

This all was wildly helpful.
A couple more questions if I dare:
1. Is it common pattern to put graphics used often in bank 8 of 128KRAM game?

2. I plan to have one tight engine for main levels and one for boss fights, both reply on data stored in ROM which would mostly likely be in additional banks that store only data. Is it possible to load data into an array structure in RAM from different bank than the one you are currently using? 

3. Do things like dim, font, alphachars, and palette settings need to be defined in a specific bank. It feels like these are mostly directives and peek/pokes/registers settings, but I could be wrong.

 

Thanks,

 

Steve

Edited by fultonbot
  • Like 1
Link to comment
Share on other sites

1. Yes, generally anything that gets shared throughout your game would go in bank 8. If you have something that only gets used once or twice that might be a good candidate for duplicating between banks.

 

2. Yes, you can jump to one bank, put some data in RAM, and then jump back to run whatever code you need to. That goes for both the normal RAM on the console and RAM on the cart (and if you have banked RAM then the RAM you copied the data to needs to be the RAM that's enabled).

 

One way to think of how the larger cartridge sizes work is as if there are 3 16k slots that they can fill. 128K and up keeps one filled with the last bank, swaps around what's in another, and either leaves the third empty of fills it with extra RAM. 144K, 272K, and 528K would be the same except instead of RAM in the third slot or leaving it empty it keeps bank 1 in it. 

  • Like 2
  • Thanks 1
Link to comment
Share on other sites

To answer your amendment -

 

3. Palettes can be set anywhere as those are held in RAM on the console so always visible. Dimensioning memory I think can be done anywhere. As for the font and alphachars, your font graphics could be anywhere but would need to be in a selected bank for it to draw properly, and as for alphachars I don't know as I've not used it much.

  • Like 1
Link to comment
Share on other sites

  • 1 year later...

I'm looking to convert Wizard's Dungeon from a 48k game to a larger bank switched ROM size as a starting point for another project.   Just changing rom size, without changing any other code, gives me this:

 

image.png.f41e8539a74b66eff9b12b2d90fd52d6.png

 

Is this because instead of one 48k contiguous block you've got 3 16k banks?  I'd have to basically separate it into 3 16k banks to get the existing code to compile?

 

Given the spaghetti mess of code that WD turned into it might be easier to start fresh, but I'd like to better understand how to manage the space.

 

[Edit] Yep, just separating out the code with bank # statements seems to work. That did it. Duh. Thanks for being my rubber duck!

Edited by BydoEmpire
  • Like 5
Link to comment
Share on other sites

While my basic bank switching is working, I'm wondering if there's a way to use graphics stored in different banks on the same screen. Doesn't *seem* like it, but I haven't quite wrapped my head around what's actually happening under the hood.  Without a frame buffer to copy the sprites into, it'd seem like whatever is being plotted just points to a location and whatever is at that location in the current bank gets drawn.

 

The code below work, I can cycle through the banks and display whatever sprite is in whatever bank, but seems kinda wasteful to have to copy the tileset in each bank.  In terms of how to organize everything, I guess I'd have to have all of the graphics for a given level in one bank, 16k limit, along with whatever code does the drawing.  An common graphics would have to be copied in each bank.  Any generic game code could be anywhere.

 

Is that correct, or am I missing something? Seems awfully restrictive, given how amazing some of the homebrews are. Either you all are wizards at squeezing great art into 16k or I'm missing something.


Bank1_MainLoop    ;'main game loop for gameplay
   
    frame=frame+1

    rem ** restore background first
    restorescreen

    rem ** draw sprites
    if cur_bank=1 then gosub Bank1_DrawElements bank1
    if cur_bank=2 then gosub Bank2_DrawElements bank2
    if cur_bank=3 then gosub Bank3_DrawElements bank3
    if cur_bank=4 then gosub Bank4_DrawElements bank4

    rem ** now actually display the screen    
    drawscreen

	.. code to change cur_bank here ...

    goto Bank1_MainLoop_Return
  /***********************************************/
    bank 1

    incgraphic gfx/tileset_wd_lvl1_alt.png 160A 0 1 2 3
    incgraphic gfx/scoredigits_8_wide_centered.png
    incgraphic gfx/alphabet_wd.png 160A 0 2 1 3 

    rem ** up left down right
    incgraphic gfx/wiz_new_l.png
    incgraphic gfx/wiz_new_l2.png
    incgraphic gfx/wiz_new_r.png
    incgraphic gfx/wiz_new_r2.png

	... bank 1 code here...

    /***********************************************/
    bank 2
    incgraphic gfx/tileset_wd_lvl1_alt.png 160A 0 1 2 3
    incgraphic gfx/scoredigits_8_wide_centered.png
    incgraphic gfx/alphabet_wd.png 160A 0 2 1 3 

    incgraphic gfx/spider1.png
    incgraphic gfx/spider2.png
    incgraphic gfx/spider3.png
    incgraphic gfx/spider4.png

	... bank 2 code here...

    /***********************************************/
    bank 3
    incgraphic gfx/tileset_wd_lvl1_alt.png 160A 0 1 2 3
    incgraphic gfx/scoredigits_8_wide_centered.png
    incgraphic gfx/alphabet_wd.png 160A 0 2 1 3 

    incgraphic gfx/bat1.png
    incgraphic gfx/bat2.png
    incgraphic gfx/bat3.png
    incgraphic gfx/bat4.png

	... bank 3 code here ...

I'm thinking about how to best organize things before I get too deep so any advice appreciated.

Link to comment
Share on other sites

Yes, everybody runs across their personal "oh my god, I need to copy my sprites/routines/whatever between several ephemeral banks" moment when they first start using bankswitching. It's a natural part of it, and an expected consequence of the banks having to share limited address space.

 

You want to organise your graphics in terms of common stuff going in the last bank, and graphics that change depending on game context (e.g. enemy graphics that change due to level progression) into those ephemeral banks. (with some duplication of things that don't change) You might also look at a 144k format, if you don't need cart ram, as that gives you another permanent bank. (asm folks can also stick the second-last bank at $4000, but for now 7800basic needs to use 144k to get a permanent bank at $4000.)

 

  • Thanks 1
Link to comment
Share on other sites

1 hour ago, RevEng said:

You want to organise your graphics in terms of common stuff going in the last bank, and graphics that change depending on game context (e.g. enemy graphics that change due to level progression) into those ephemeral banks. (with some duplication of things that don't change) You might also look at a 144k format, if you don't need cart ram, as that gives you another permanent bank. (asm folks can also stick the second-last bank at $4000, but for now 7800basic needs to use 144k to get a permanent bank at $4000.)

 

Ah, cool, so for all formants the last bank is always resident?

Link to comment
Share on other sites

On 3/13/2022 at 6:46 AM, RevEng said:

Yes, everybody runs across their personal "oh my god, I need to copy my sprites/routines/whatever between several ephemeral banks" moment when they first start using bankswitching. It's a natural part of it, and an expected consequence of the banks having to share limited address space.

When Mike first explained this to me it seemed counterproductive but I've used it regularly since. In Millie & Molly due to the way I designed the levels, banks 2 & 3 contain essentially the same code - all it did was tag the method names with BankX and as I made changes I could copy/rename/paste into the other bank. Made it very simple to keep insync.

  • Like 5
Link to comment
Share on other sites

51 minutes ago, mksmith said:

When Mike first explained this to me it seemed counterproductive but I've used it regularly since. In Millie & Molly due to the way I designed the levels, banks 2 & 3 contain essentially the same code - all it did was tag the method names with BankX and as I made changes I could copy/rename/paste into the other bank. Made it very simple to keep insync.

I used the exact same method for EXO after Mike and Matt's great advice.

  • Like 4
Link to comment
Share on other sites

It hasn't been too bad once I started from scratch. Trying to convert an existing game, which had a lot of hackery put in it squeeze it down to 48k, was messy. Now I know what I'm shooting for in each bank and can think about organization, adding (and testing) each piece at a time. Much easier. The advice on this thread is much appreciated, it got me going way faster than it would have been otherwise.

Quote

all it did was tag the method names with BankX and as I made changes I could copy/rename/paste into the other bank

Hah, I did the exact same thing. Good to know it's a proven approach.

Edited by BydoEmpire
  • Like 4
Link to comment
Share on other sites

How frequently can you realistically gosub to different banks while building the screen?  I'm seeing the top row of tiles get cut off, but I'm jumping back and forth between bank 1 (the loop this is in), bank 2 & 3 (the level's tiles and sprites) and bank 16 (resident bank w/ default text, the hero character, etc). I'm trying to avoid as much duplicate code as possible but maybe that's the price you pay... 
 

   clearscreen

    rem ** each level sets up the default room
    if cur_level <> 3 then gosub Bank2_InitRoom bank2
    if cur_level = 3 then gosub Bank3_InitRoom bank3        ; for now, just two levels to test

    rem ** generically read the map and poke NSEW doors
    gosub Bank16_MakeDoors

    rem ** now draw room details
    if cur_level <> 3 then gosub Bank2_DrawRoomDetails bank2
    if cur_level = 3 then gosub Bank3_DrawRoomDetails bank3        ; for now, just two levels to test

    rem ** draw any common room details (like text)
    gosub Bank16_DrawRoomDetails

    rem ** this way we don't setup the background over and over again.
    savescreen
    drawscreen

 

Edited by BydoEmpire
Link to comment
Share on other sites

Hm, I think the bug is elsewhere (though perhaps related). I moved all the Bank16_* code into bank 2 and it still happens. I noticed when I move the hero character sprite around the top row of tiles gets cut off more, which I assume means it's not really related to building the screen (as in the above code)...  I am wondering how valid it is to do this kind of thing, but I'll keep digging around.

 

[edit] Wait a minute, if banks 1 and 16 are always resident, then it really shouldn't matter if I jump to at least one other bank in between... I think I answered my own question. Probably a bug elsewhere as I moved code around.

Edited by BydoEmpire
Link to comment
Share on other sites

  • 2 months later...

In a way, you can use the multiple banks to do continiuous animation. The more banks you have (Ex: 12 4K banks) the more freedom you have. For example, let's make a made up mapper where you get 11 4K banks at once. $4000-$5000 is RAM plus some controll variables. You can only "See" 11 4K banks but there could be 16 possible 4K banks for each 4K of ROM above $5000. So that would mean, 11*16*4 = 704 kilobytes of ROM, plus 4K of RAM, or maybe even SRAM.

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