Jump to content
  • entries
    106
  • comments
    796
  • views
    140,753

Switching Banks Made Easy?


Guest

954 views

THIS IS KINDA TECHNICAL, I suppose.While I don't expect to ever actually complete a VCS Metroid port, for various reasons, I am going forward with it right now. I've targeted it for a 32K cart, and I've been thinking a bit about the best way to switch banks.This is what I've come up with:Call a subroutine in another bank with this code:

   brk
  .word Subroutine

Have the break vector point to this subroutine (copied in every bank):

  plp

  tsx

  inx

  dec $00,X

  lda ($00, X

  sta MiscPtr

  inc $00,X

  lda ($00,X)

  sta MiscPtr+1

  lsr

  lsr

  lsr

  lsr

  lsr

  tax

  nop $1FF4,X

Assuming I had ORGed all my banks to addresses of this form:

0xxxxx, 1xxxxx, %010xxxxx, %011xxxxx, etc.

This would switch to another bank, and at that point the program would encounter this code:

   jmp (MiscPtr)

Which would begin the subroutine. At the end of the subroutine I would have this code:

   jmp ReturnFromBSSubroutine

Which would go here:

ReturnFromBSSubroutine

  tsx

  inx

  inx

  lda $00,X      ;get high byte of return address

  lsr

  lsr

  lsr

  lsr

  lsr

  tax

  nop $1FF4,X

Which would switch banks to this address:

   rts

I suppose I could do all this with a JSR instruction also, and save the BRK vector for something else...Anyway. Assuming that this all works (I just dreamed it up this morning, so who knows), it would have these advantages:

1. I wouldn't need to maintain tables of jump addresses in multiple banks.

2. I could move subroutines around freely without having to find and change all the entry/exit points.

3. It is really easy to use. In every bank, at any point, just one opcode plus an address.

4. It uses 4 bytes of RAM: 2 on the stack plus 2 for MiscPtr. If those 4 are contiguous. If not, it takes 5 (since BRK also pushes the flags). Could use JSR to avoid pushing the flags.

 

Disadvantages:

1. It takes a loooooong time to switch banks. Almost a whole scanline to go to a subroutine and almost half a scanline to come back.

2. I don't have to duplicate any tables, but I do have to duplicate all that code in every bank.

3. Probably something else.

 

Basically, I want to avoid the issues I had with Reindeer Runner, where I used a really stupid way to switch banks, which backfired on me when I ended up having to move things from one bank to another.

 

Anybody else have any better ways to do this? I'm looking for a method that:

1. Allows me to call subroutines in other banks and return to the point from which they were called.

2. Not have to maintain and duplicate tables of jump addresses, though that isn't a deal-killer

3. Is fast.

4. Doesn't use a ton of RAM.

5. Allows me to move subroutines around (from bank to bank) without having to spend an hour tracking down and changing jmp addresses.

3 Comments


Recommended Comments

bB's bankswitching uses a similar concept, but yours is easier for asm work (with the indexed indirect stuff.) I see a couple ways to improve it (I think, I could be wrong...)

  brk
 .word Subroutine-1

...

 plp
 tsx
 inx
; dec $00,X - not needed due to above
 lda ($00, X)
 sta MiscPtr
 inc $00,X
 lda ($00,X)
 sta MiscPtr+1
 lsr
 lsr
 lsr
 lsr
 lsr
 tax
 nop $1FF4,X

...

ReturnFromBSSubroutine
 tsx
 lda 2,X     ;get high byte of return address
 lsr
 lsr
 lsr
 lsr
 lsr
 tax
 nop $1FF2,X

 

That said, I know that bB's BS method could use some improvement too! I have been meaning to check to see if indexed indirect used fewer cycles, but I've been too lazy to count them.

Link to comment

EDIT: Cut out my stupidity. :)

 

EDIT II: Ok, complete edit now. I now see what you are doing.

 

That is nice, would save 6 cycles by eliminating the DEC ZP, X instruction, plus save four more on the way back.

 

Just saw - I could cut out the initial INX also and do this...

  ;--BRK vector points here
  plp
  tsx
  lda ($01, X)
  sta MiscPtr
  inc $01, X
  lda ($01, X)
  sta MiscPtr+1
  lsr
  lsr
  lsr
 ;--etc.

Link to comment

The approach using indirect-Y addressing eliminates the bug which could hit if the BRK occurred just before a page boundary, but requires that the stacking address be known. IMHO, the BRK-based approaches are probably overkill unless code space or RAM are really tight (in which case you could generate a table listing all of the calls used by the program--most 2600-sized programs will have fewer than 128 subroutine calls within them). Use two tables--one for MSB/bank and the other for LSB. The BRK sequence would be, basically:

 

-1- Fetch the byte following the BRK instruction

 

-2- Pop all three pushed bytes off the stack and push that byte and that byte+1

 

-3- Jump to the "pseudo-RTS" routine which will pop the top byte from the stack, look it up in the lsb/msb tables, stash it someplace, and indirect-jump there.

 

This would require a little temp. stack space, but that could be easily overlayed with other kernel variables.

 

Otherwise, the approach I use in Strat-O-Gems is to define a macro called HEADERS which is .rorg'ed at the same address in every bank. It looks something like:

RESET:
 nop BANK1
 jmp V_RESET
KERNEL:
 nop BANK2
 jmp V_KERNEL
RTS1:
 nop BANK1
 rts
KERNEL_B3
 nop BANK2
 jsr V_KERNEL
 nop BANK3
 jmp KERNEL_B3_RET

Most routines will always be invoked from the same bank so they can end with a JMP to the appropriate RTS routine. There are sufficiently few cases where a routine is called from a 'funny' bank that I can handle those explicitly (as in the KERNEL_B3 example).

 

A call to another bank takes 6+3+3=12 cycles. A return to another bank takes 3+3+6 (also 12) cycles. An "unusual" call to another bank still takes 12 cycles (3+3+6) but the return takes 12+3+3=18 cycles (the first return goes into the KERNEL_B3 code, which then takes 6 more cycles to reach the proper destination).

 

Not quite as fast as FE-based bank-switching, but more versatile.

Link to comment
Guest
Add a comment...

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