Jump to content
Just Jeff

Games over 4K

Recommended Posts

Hi.

 

The easiest way is to use the standard F8 method.

 

At top of ROM put same reset address in both 4k banks and select one of the banks doing LDA $FFF8 (bank 0) or LDA $FFF9 (bank 1)

 

The whole 4K bank is replaced and next instruction will be read from the selected bank.

  • Like 1

Share this post


Link to post
Share on other sites

Usually you would do this by having a group of labels either at the beginning or end of each bank, one for each address in other banks that you want to be able to jump to from that bank. To switch banks, you jump to the label you want, which selects the bank, and then after it is switched, jumps to the actual address you want to get to. You have to make sure the bank switching instructions line up with the following instructions on the next bank, because the program counter doesn't change when the bank switches, it marches on from wherever it was.

  • Like 1

Share this post


Link to post
Share on other sites

Another option, if you can use a couple bytes of temp RAM, is to use an indirect jump. Load the desired final address into a pointer, and jump to the label that switches to the desired bank. From there do an indirect jump to the pointer.

  • Like 1

Share this post


Link to post
Share on other sites

Thanks again! So F6 looks pretty much the same as F8, but for 4- 4K banks. I think that one looks good. To your earlier post- I'm writing up a routine right now that uses a lot of indirect jumps so that would work nicely here..

Edited by BNE Jeff

Share this post


Link to post
Share on other sites

The way I did it in Medieval Mayhem seemed like a logical way to do it. I used macros JUMP_TABLE and BANKS_AND_VECTORS at the start and end of every bank. MM's a 32K game so there's 8 banks, the same technique will work work fewer banks.

 

        MAC JUMP_TABLE ; put this at the start of every bank
        RORG $F000
InitSystem
        cmp SelectBank5   ; inits system then goes to the menu
        jmp InitSystemCode
VerticalBlankMenu
        cmp SelectBank8
        jmp VerticalBlankMenuCode
KernelMenu
	cmp SelectBank6
	jmp KernelMenuCode
VerticalBlankGame
        cmp SelectBank1
        jmp VerticalBlankGameCode
KernelGame
        cmp SelectBank8    ; draws score, top castles, dragons
        jmp KernelGameCode
KernelGameDragon
        cmp SelectBank2    ; draws bottom castles
        jmp KernelGameDragonCode
KernelGameDragon2
        cmp SelectBank3    ; draws bottom castles
        jmp KernelGameDragon2Code
KernelGameBottom
        cmp SelectBank5    ; draws bottom castles
        jmp KernelGameBottomCode
OverscanMenu2             ; Menu Entry Point if user hits SELECT
        cmp SelectBank6   ; or RESET during a game
        jmp OverscanMenu2Code
OverscanGame
        cmp SelectBank7
        jmp OverscanGameCode
OverscanGame2
        cmp SelectBank2
        jmp OverscanGame2Code
StartRound
        cmp SelectBank8
        jmp StartRoundCode
        ENDM

        MAC BANKS_AND_VECTORS ; put this at the end of every bank
        RORG $FFF4
SelectBank1 .byte $00
SelectBank2 .byte $00
SelectBank3 .byte $00
SelectBank4 .byte $00
SelectBank5 .byte $00
SelectBank6 .byte $00
SelectBank7 .byte $00
SelectBank8 .byte $00
;       .word InitSystem ; 7 and 8 overlap NMI
        .word InitSystem ; RESET
        .word InitSystem ; IRQ
        ENDM

 

You can find the source in the Medieval Mayhem blog entries.

  • Like 4

Share this post


Link to post
Share on other sites

Neat..

 

Trying to grasp it..

 

The CMPs cause the processor to read from an address at $FFF4 through $FFFC. Value of zero in those locations is irrelevant.

The access causes the bank switch somehow.

The following jump statement is executed in the new bank or does it execute when it returns?

Share this post


Link to post
Share on other sites

Yep, as soon as $FFF4 thru $FFFC are accessed the bank is switched.

 

I do recommend changing those to NOP instead of CMP as the CMP will set various flags which can cause unintended results to occur in your code. I wasn't aware of the illegal opcode variations of NOP at the time.

  • Like 2

Share this post


Link to post
Share on other sites

Alright..

 

I managed to turn my "framework" code into a 32k bin with the help of the Medieval Mayhem blog. I put all of it in bank 5. Its not working yet though. It looks like its running through the reset routine, then pointing to a RAM address then resetting again. These labels look wrong too, Its adding "Game" to some of them, "InitSystem" Isn't my label for that routine, and labels are missing for SelectBank1 and SelectBank2 in MAC BANKS_AND_VECTORS. Also, my VerticalSync routine isn't there.

post-44582-0-64267100-1514727650_thumb.jpg

post-44582-0-53585900-1514727632_thumb.jpg

32KGame.asm

32KGame.bin

Edited by BNE Jeff

Share this post


Link to post
Share on other sites

Alright..

 

I managed to turn my "framework" code into a 32k bin with the help of the Medieval Mayhem blog. I put all of it in bank 5. Its not working yet though. It looks like its running through the reset routine, then pointing to a RAM address then resetting again. These labels look wrong too, Its adding "Game" to some of them, "InitSystem" Isn't my label for that routine, and labels are missing for SelectBank1 and SelectBank2 in MAC BANKS_AND_VECTORS. Also, my VerticalSync routine isn't there.

The code didn't compile correctly. You need to use ORG to define where the code goes in the physical rom, an RORG to give it a valid ROM space address.

 

Valid rom space for a 2600 game is:

$1xxx

$3xxx

$5xxx

$7xxx

$9xxx

$Bxxx

$Dxxx

$Fxxx

 

You can do someting like this:

ORG $C000

RORG $F000

 

You can RORG to addresses you have used before.

  • Like 1

Share this post


Link to post
Share on other sites

Ahh... Thank you..

 

Yeah RORG is new to me.. I think I have a basic idea of what its doing now.. In this case the macro JUMP_TABLE contains the RORG and I just had the macro in the wrong place:
post-44582-0-50561400-1514799804_thumb.jpg

So, I moved it up under ORG $C000 and now the code is working..

 

Thanks Again!

Share this post


Link to post
Share on other sites

So I'm curious how this works.. Is there a little bit of extra hardware in the cartridge that "listens" in on those addresses and then directs the bus to a bank? Perhaps a simple set of transistors turned high by the read? (I'm not an electronics whiz)

Share this post


Link to post
Share on other sites

So I'm curious how this works.. Is there a little bit of extra hardware in the cartridge that "listens" in on those addresses and then directs the bus to a bank? Perhaps a simple set of transistors turned high by the read? (I'm not an electronics whiz)

 

There is extra hardware in the cart. A flip flop and some NAND gates to drive it. See this thread http://atariage.com/forums/topic/5508-bankswitching-f8/

 

Edit: This is how it would have been done back in the day. See below for how it's done now.

Edited by CurtisP
  • Like 1

Share this post


Link to post
Share on other sites

 

Or a PLD (Programmable Logic Device), such as a 22V10, that contains the bankswitching logic and can be programmed to support a variety of bankswitching methods.

 

..Al

In other words, flash a Melody board and call it a day?

Edited by CurtisP
  • Like 1

Share this post


Link to post
Share on other sites

In other words, flash a Melody board and call it a day?

 

Well, that's taking it to an entire new level, given the Melody board has an onboard ARM processor. That's generally what I use, though, when testing games on real hardware during development.

 

..Al

  • Like 1

Share this post


Link to post
Share on other sites

The way I did it in Medieval Mayhem seemed like a logical way to do it. I used macros JUMP_TABLE and BANKS_AND_VECTORS at the start and end of every bank. MM's a 32K game so there's 8 banks, the same technique will work work fewer banks.

 

        MAC JUMP_TABLE ; put this at the start of every bank
        RORG $F000
InitSystem
        cmp SelectBank5   ; inits system then goes to the menu
        jmp InitSystemCode
VerticalBlankMenu
        cmp SelectBank8
        jmp VerticalBlankMenuCode
KernelMenu
	cmp SelectBank6
	jmp KernelMenuCode
VerticalBlankGame
        cmp SelectBank1
        jmp VerticalBlankGameCode
KernelGame
        cmp SelectBank8    ; draws score, top castles, dragons
        jmp KernelGameCode
KernelGameDragon
        cmp SelectBank2    ; draws bottom castles
        jmp KernelGameDragonCode
KernelGameDragon2
        cmp SelectBank3    ; draws bottom castles
        jmp KernelGameDragon2Code
KernelGameBottom
        cmp SelectBank5    ; draws bottom castles
        jmp KernelGameBottomCode
OverscanMenu2             ; Menu Entry Point if user hits SELECT
        cmp SelectBank6   ; or RESET during a game
        jmp OverscanMenu2Code
OverscanGame
        cmp SelectBank7
        jmp OverscanGameCode
OverscanGame2
        cmp SelectBank2
        jmp OverscanGame2Code
StartRound
        cmp SelectBank8
        jmp StartRoundCode
        ENDM

        MAC BANKS_AND_VECTORS ; put this at the end of every bank
        RORG $FFF4
SelectBank1 .byte $00
SelectBank2 .byte $00
SelectBank3 .byte $00
SelectBank4 .byte $00
SelectBank5 .byte $00
SelectBank6 .byte $00
SelectBank7 .byte $00
SelectBank8 .byte $00
;       .word InitSystem ; 7 and 8 overlap NMI
        .word InitSystem ; RESET
        .word InitSystem ; IRQ
        ENDM

 

You can find the source in the Medieval Mayhem blog entries.

 

 

Can this same method be used to make 64 K game?

Share this post


Link to post
Share on other sites

Sure. But the more banks you have, the more likely your code accesses multiple banks and the longer and more complicated to maintain the bankswitching list becomes.

 

So something less straightforward and bit more sophisticated (and slower) seems more appropriate. E.g.

  bit SelectBank1,y ; y = bank number
  jmp (vector)      ; vector setup by calling code e.g via macro

Therefore I have created certain bankswitching macros on my own, which even make bankswitching transparent, so they are quite convenient to use. I can post them here when I am back at home.

Edited by Thomas Jentzsch
  • Like 3

Share this post


Link to post
Share on other sites

Depends upon the bankswitch scheme. I've not kept up with board developments, just checked and see UnoCart supports 3F, EF and F0 for 64K. I checked Stella's source to see how they work:

 

3F - Has thirty-two 2K banks. The first 2K of cartridge space ($F000-F7FF) get swapped, last 2K is always mapped to the last 2K bank. Bankswitch is done by writing the desired bank to address $3F.

 

EF - has sixteen 4K banks. Uses $1FE0 - $1FEF to select bank, so would need to adjust the BANKS_AND_VECTORS.

 

F0 - has sixteen 4K banks. Accessing $1FF0 switches to next bank, so you don't get to arbitrarily select a bank.

 

 

So of those EF could be made to work with my example. As Thomas mentions, if you do it this way the overhead increases (as more of each 4K bank is dedicated to bank switching code) so finding a better way to do it would be in your best interesting.

 

One side affect of my switching to ARM support for my games is they only use 1 bank of 6507 code, and the ARM sees everything without needing to bankswitch, so I've not looked into better ways to do it.

  • Like 1

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